This means that most loose refs will no longer be present after the rename
which triggered a test failure since it assumes the file for an unrelated
ref would still be present after the rename. This also makes the rename
itself slightly slower, but as it now results in all refs being packed future
commands accessing refs might become slightly faster.

We want to do this to make it easier to handle atomic renames in rename_ref for
the case 'git branch -m foo/bar foo'. If we can guarantee that foo/bar does not
exist as a loose ref we can avoid locking foo/bar.lock during transaction
commit and thus make it possible to delete the foo directory and re-create
it as a file(branch) in a single transaction.

There is a small race between when we pack all refs and we eventually remove
the old ref from the packed refs file. If a concurrent process deletes the old
ref from the packed refs file, then creates a new ref with that name and
finally repacks the packed refs file, then our transaction will delete the new
ref without realizing it had changed during the transaction. The window for this
is very short and is still a slightly less race than the ones in the old
code for ref_rename.

Reviewed-by: Jonathan Nieder <>
Signed-off-by: Ronnie Sahlberg <>
 refs.c            | 3 +++
 t/ | 6 +++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/refs.c b/refs.c
index 8848dbf..03cff59 100644
--- a/refs.c
+++ b/refs.c
@@ -2652,6 +2652,9 @@ int rename_ref(const char *oldrefname, const char 
*newrefname, const char *logms
                return error("unable to move logfile logs/%s to 
                        oldrefname, strerror(errno));
+       if (pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE))
+               return error("unable to pack refs");
        if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
                error("unable to delete old %s", oldrefname);
                goto rollback;
diff --git a/t/ b/t/
index ac31b71..de0c2b9 100755
--- a/t/
+++ b/t/
@@ -288,9 +288,9 @@ test_expect_success 'deleting a dangling symref' '
 test_expect_success 'renaming a symref is not allowed' '
        git symbolic-ref refs/heads/master2 refs/heads/master &&
        test_must_fail git branch -m master2 master3 &&
-       git symbolic-ref refs/heads/master2 &&
-       test_path_is_file .git/refs/heads/master &&
-       test_path_is_missing .git/refs/heads/master3
+       git rev-parse --verify refs/heads/master &&
+       test_must_fail git symbolic-ref refs/heads/master3 &&
+       test_must_fail git rev-parse refs/heads/master3
 test_expect_success SYMLINKS 'git branch -m u v should fail when the reflog 
for u is a symlink' '

To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to
More majordomo info at

Reply via email to