OSDN Git Service

lock_ref_sha1_basic(): improve diagnostics for ref D/F conflicts
authorMichael Haggerty <mhagger@alum.mit.edu>
Mon, 11 May 2015 15:25:16 +0000 (17:25 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 18:50:20 +0000 (11:50 -0700)
If there is a failure to lock a reference that is likely caused by a
D/F conflict (e.g., trying to lock "refs/foo/bar" when reference
"refs/foo" already exists), invoke verify_refname_available() to try
to generate a more helpful error message.

That function might not detect an error. For example, some
non-reference file might be blocking the deletion of an
otherwise-empty directory tree, or there might be a race with another
process that just deleted the offending reference. In such cases,
generate the strerror-based error message like before.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
refs.c
t/t1404-update-ref-df-conflicts.sh

diff --git a/refs.c b/refs.c
index ff9b9cf..ce993bd 100644 (file)
--- a/refs.c
+++ b/refs.c
@@ -2369,8 +2369,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
                ref_file = git_path("%s", orig_refname);
                if (remove_empty_directories(ref_file)) {
                        last_errno = errno;
-                       strbuf_addf(err, "there are still refs under '%s'",
-                                   orig_refname);
+
+                       if (!verify_refname_available(orig_refname, extras, skip,
+                                                     get_loose_refs(&ref_cache), err))
+                               strbuf_addf(err, "there are still refs under '%s'",
+                                           orig_refname);
+
                        goto error_return;
                }
                refname = resolve_ref_unsafe(orig_refname, resolve_flags,
@@ -2380,8 +2384,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
            *type_p = type;
        if (!refname) {
                last_errno = errno;
-               strbuf_addf(err, "unable to resolve reference %s: %s",
-                           orig_refname, strerror(errno));
+               if (last_errno != ENOTDIR ||
+                   !verify_refname_available(orig_refname, extras, skip,
+                                             get_loose_refs(&ref_cache), err))
+                       strbuf_addf(err, "unable to resolve reference %s: %s",
+                                   orig_refname, strerror(last_errno));
+
                goto error_return;
        }
        /*
index 6d6200a..66bafb5 100755 (executable)
@@ -36,7 +36,7 @@ test_expect_success 'existing loose ref is a simple prefix of new' '
 
        prefix=refs/1l &&
        test_update_rejected $prefix "a c e" false "b c/x d" \
-               "unable to resolve reference $prefix/c/x: Not a directory"
+               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
 
 '
 
@@ -52,7 +52,7 @@ test_expect_success 'existing loose ref is a deeper prefix of new' '
 
        prefix=refs/2l &&
        test_update_rejected $prefix "a c e" false "b c/x/y d" \
-               "unable to resolve reference $prefix/c/x/y: Not a directory"
+               "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
 
 '
 
@@ -68,7 +68,7 @@ test_expect_success 'new ref is a simple prefix of existing loose' '
 
        prefix=refs/3l &&
        test_update_rejected $prefix "a c/x e" false "b c d" \
-               "there are still refs under $Q$prefix/c$Q"
+               "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
 
 '
 
@@ -84,7 +84,7 @@ test_expect_success 'new ref is a deeper prefix of existing loose' '
 
        prefix=refs/4l &&
        test_update_rejected $prefix "a c/x/y e" false "b c d" \
-               "there are still refs under $Q$prefix/c$Q"
+               "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
 
 '