When renaming refs, don't dereference either the origin or the destination
before renaming.

The origin does not need to be dereferenced because it is presently
forbidden to rename symbolic refs.

Not dereferencing the destination fixes a bug where renaming on top of
a broken symref would use the pointed-to ref name for the moved
reflog.

Add a test for the reflog bug.

Signed-off-by: David Turner <dtur...@twopensource.com>
---
 refs/files-backend.c | 15 +++++++++------
 t/t3200-branch.sh    |  9 +++++++++
 2 files changed, 18 insertions(+), 6 deletions(-)

diff --git a/refs/files-backend.c b/refs/files-backend.c
index 592d0ff..4863b21 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -2428,7 +2428,7 @@ static int files_rename_ref(const char *oldrefname, const 
char *newrefname,
                            const char *logmsg)
 {
        unsigned char sha1[20], orig_sha1[20];
-       int flag = 0, logmoved = 0;
+       int flag = 0, logmoved = 0, resolve_flags;
        struct ref_lock *lock;
        struct stat loginfo;
        int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
@@ -2438,7 +2438,8 @@ static int files_rename_ref(const char *oldrefname, const 
char *newrefname,
        if (log && S_ISLNK(loginfo.st_mode))
                return error("reflog for %s is a symlink", oldrefname);
 
-       symref = resolve_ref_unsafe(oldrefname, RESOLVE_REF_READING,
+       resolve_flags = RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE;
+       symref = resolve_ref_unsafe(oldrefname, resolve_flags,
                                    orig_sha1, &flag);
        if (flag & REF_ISSYMREF)
                return error("refname %s is a symbolic ref, renaming it is not 
supported",
@@ -2458,8 +2459,8 @@ static int files_rename_ref(const char *oldrefname, const 
char *newrefname,
                goto rollback;
        }
 
-       if (!read_ref_full(newrefname, RESOLVE_REF_READING, sha1, NULL) &&
-           delete_ref(newrefname, sha1, REF_NODEREF)) {
+       if (!read_ref_full(newrefname, resolve_flags, sha1, NULL) &&
+           delete_ref(newrefname, NULL, REF_NODEREF)) {
                if (errno==EISDIR) {
                        struct strbuf path = STRBUF_INIT;
                        int result;
@@ -2483,7 +2484,8 @@ static int files_rename_ref(const char *oldrefname, const 
char *newrefname,
 
        logmoved = log;
 
-       lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, 0, NULL, &err);
+       lock = lock_ref_sha1_basic(newrefname, NULL, NULL, NULL, REF_NODEREF,
+                                  NULL, &err);
        if (!lock) {
                error("unable to rename '%s' to '%s': %s", oldrefname, 
newrefname, err.buf);
                strbuf_release(&err);
@@ -2501,7 +2503,8 @@ static int files_rename_ref(const char *oldrefname, const 
char *newrefname,
        return 0;
 
  rollback:
-       lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, 0, NULL, &err);
+       lock = lock_ref_sha1_basic(oldrefname, NULL, NULL, NULL, REF_NODEREF,
+                                  NULL, &err);
        if (!lock) {
                error("unable to lock %s for rollback: %s", oldrefname, 
err.buf);
                strbuf_release(&err);
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index cdaf6f6..07e9749 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -79,6 +79,15 @@ test_expect_success 'git branch -m dumps usage' '
        test_i18ngrep "branch name required" err
 '
 
+test_expect_success 'git branch -m m broken_symref should work' '
+       test_when_finished "git branch -D broken_symref" &&
+       git branch -l m &&
+       git symbolic-ref refs/heads/broken_symref refs/heads/i_am_broken &&
+       git branch -m m broken_symref &&
+       git reflog exists refs/heads/broken_symref &&
+       test_must_fail git reflog exists refs/heads/i_am_broken
+'
+
 test_expect_success 'git branch -m m m/m should work' '
        git branch -l m &&
        git branch -m m m/m &&
-- 
2.4.2.767.g62658d5-twtrsrc

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to