Merge branch 'jk/refs-df-conflict'

An ancient bug that made Git misbehave with creation/renaming of
refs has been fixed.

* jk/refs-df-conflict:
  refs_resolve_ref_unsafe: handle d/f conflicts for writes
  t3308: create a real ref directory/file conflict
This commit is contained in:
Junio C Hamano 2017-10-11 14:52:23 +09:00
commit bab02c6e63
4 changed files with 50 additions and 3 deletions

15
refs.c
View File

@ -1435,8 +1435,21 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
if (refs_read_raw_ref(refs, refname,
sha1, &sb_refname, &read_flags)) {
*flags |= read_flags;
if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
/* In reading mode, refs must eventually resolve */
if (resolve_flags & RESOLVE_REF_READING)
return NULL;
/*
* Otherwise a missing ref is OK. But the files backend
* may show errors besides ENOENT if there are
* similarly-named refs.
*/
if (errno != ENOENT &&
errno != EISDIR &&
errno != ENOTDIR)
return NULL;
hashclr(sha1);
if (*flags & REF_BAD_NAME)
*flags |= REF_ISBROKEN;

View File

@ -129,11 +129,35 @@ 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' '
test_expect_success 'symbolic-ref can overwrite pointer to invalid name' '
test_when_finished reset_to_sane &&
head=$(git rev-parse HEAD) &&
git symbolic-ref HEAD refs/heads/outer &&
test_when_finished "git update-ref -d refs/heads/outer/inner" &&
git update-ref refs/heads/outer/inner $head &&
git symbolic-ref HEAD refs/heads/unrelated
'
test_expect_success 'symbolic-ref can resolve d/f name (EISDIR)' '
test_when_finished reset_to_sane &&
head=$(git rev-parse HEAD) &&
git symbolic-ref HEAD refs/heads/outer/inner &&
test_when_finished "git update-ref -d refs/heads/outer" &&
git update-ref refs/heads/outer $head &&
echo refs/heads/outer/inner >expect &&
git symbolic-ref HEAD >actual &&
test_cmp expect actual
'
test_expect_success 'symbolic-ref can resolve d/f name (ENOTDIR)' '
test_when_finished reset_to_sane &&
head=$(git rev-parse HEAD) &&
git symbolic-ref HEAD refs/heads/outer &&
test_when_finished "git update-ref -d refs/heads/outer/inner" &&
git update-ref refs/heads/outer/inner $head &&
echo refs/heads/outer >expect &&
git symbolic-ref HEAD >actual &&
test_cmp expect actual
'
test_done

View File

@ -117,6 +117,16 @@ test_expect_success 'git branch -m bbb should rename checked out branch' '
test_cmp expect actual
'
test_expect_success 'renaming checked out branch works with d/f conflict' '
test_when_finished "git branch -D foo/bar || git branch -D foo" &&
test_when_finished git checkout master &&
git checkout -b foo &&
git branch -m foo/bar &&
git symbolic-ref HEAD >actual &&
echo refs/heads/foo/bar >expect &&
test_cmp expect actual
'
test_expect_success 'git branch -m o/o o should fail when o/p exists' '
git branch o/o &&
git branch o/p &&

View File

@ -79,7 +79,7 @@ test_expect_success 'fail to merge empty notes ref into empty notes ref (z => y)
test_expect_success 'fail to merge into various non-notes refs' '
test_must_fail git -c "core.notesRef=refs/notes" notes merge x &&
test_must_fail git -c "core.notesRef=refs/notes/" notes merge x &&
mkdir -p .git/refs/notes/dir &&
git update-ref refs/notes/dir/foo HEAD &&
test_must_fail git -c "core.notesRef=refs/notes/dir" notes merge x &&
test_must_fail git -c "core.notesRef=refs/notes/dir/" notes merge x &&
test_must_fail git -c "core.notesRef=refs/heads/master" notes merge x &&