summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--refs/files-backend.c19
-rwxr-xr-xt/t1401-symbolic-ref.sh7
-rwxr-xr-xt/t2011-checkout-invalid-head.sh33
3 files changed, 50 insertions, 9 deletions
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 69c3ecf..81c92b4 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -1887,7 +1887,8 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
const char *orig_refname = refname;
struct ref_lock *lock;
int last_errno = 0;
- int type, lflags;
+ int type;
+ int lflags = 0;
int mustexist = (old_sha1 && !is_null_sha1(old_sha1));
int resolve_flags = 0;
int attempts_remaining = 3;
@@ -1898,10 +1899,11 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
if (mustexist)
resolve_flags |= RESOLVE_REF_READING;
- if (flags & REF_DELETING) {
+ if (flags & REF_DELETING)
resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME;
- if (flags & REF_NODEREF)
- resolve_flags |= RESOLVE_REF_NO_RECURSE;
+ if (flags & REF_NODEREF) {
+ resolve_flags |= RESOLVE_REF_NO_RECURSE;
+ lflags |= LOCK_NO_DEREF;
}
refname = resolve_ref_unsafe(refname, resolve_flags,
@@ -1937,6 +1939,10 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
goto error_return;
}
+
+ if (flags & REF_NODEREF)
+ refname = orig_refname;
+
/*
* If the ref did not exist and we are creating it, make sure
* there is no existing packed ref whose name begins with our
@@ -1952,11 +1958,6 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
lock->lk = xcalloc(1, sizeof(struct lock_file));
- lflags = 0;
- if (flags & REF_NODEREF) {
- refname = orig_refname;
- lflags |= LOCK_NO_DEREF;
- }
lock->ref_name = xstrdup(refname);
lock->orig_ref_name = xstrdup(orig_refname);
strbuf_git_path(&ref_file, "%s", refname);
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index 5db876c..a713766 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -122,4 +122,11 @@ test_expect_success 'symbolic-ref does not create ref d/f conflicts' '
test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df
'
+test_expect_success 'symbolic-ref handles existing pointer to invalid name' '
+ head=$(git rev-parse HEAD) &&
+ git symbolic-ref HEAD refs/heads/outer &&
+ git update-ref refs/heads/outer/inner $head &&
+ git symbolic-ref HEAD refs/heads/unrelated
+'
+
test_done
diff --git a/t/t2011-checkout-invalid-head.sh b/t/t2011-checkout-invalid-head.sh
index d444d5e..c5501b0 100755
--- a/t/t2011-checkout-invalid-head.sh
+++ b/t/t2011-checkout-invalid-head.sh
@@ -25,4 +25,37 @@ test_expect_success 'checkout notices failure to lock HEAD' '
test_must_fail git checkout -b other
'
+test_expect_success 'create ref directory/file conflict scenario' '
+ git update-ref refs/heads/outer/inner master &&
+
+ # do not rely on symbolic-ref to get a known state,
+ # as it may use the same code we are testing
+ reset_to_df () {
+ echo "ref: refs/heads/outer" >.git/HEAD
+ }
+'
+
+test_expect_success 'checkout away from d/f HEAD (unpacked, to branch)' '
+ reset_to_df &&
+ git checkout master
+'
+
+test_expect_success 'checkout away from d/f HEAD (unpacked, to detached)' '
+ reset_to_df &&
+ git checkout --detach master
+'
+
+test_expect_success 'pack refs' '
+ git pack-refs --all --prune
+'
+
+test_expect_success 'checkout away from d/f HEAD (packed, to branch)' '
+ reset_to_df &&
+ git checkout master
+'
+
+test_expect_success 'checkout away from d/f HEAD (packed, to detached)' '
+ reset_to_df &&
+ git checkout --detach master
+'
test_done