lock_ref_sha1_basic(): improve diagnostics for ref D/F conflicts

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>

Michael Haggerty committed May 11, 2015 at 17:25 UTC 5b2d8d6f2184381b76c13504a2f5ec8a62cd584e
2 files changed +16 -8
refs.c
+12 -4
@@ -2369,8 +2369,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
2369 ref_file = git_path("%s", orig_refname);
2370 if (remove_empty_directories(ref_file)) {
2371 last_errno = errno;
2372 - strbuf_addf(err, "there are still refs under '%s'",
2373 - orig_refname);
2372 +
2373 + if (!verify_refname_available(orig_refname, extras, skip,
2374 + get_loose_refs(&ref_cache), err))
2375 + strbuf_addf(err, "there are still refs under '%s'",
2376 + orig_refname);
2377 +
2378 goto error_return;
2379 }
2380 refname = resolve_ref_unsafe(orig_refname, resolve_flags,
@@ -2380,8 +2384,12 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname,
2384 *type_p = type;
2385 if (!refname) {
2386 last_errno = errno;
2383 - strbuf_addf(err, "unable to resolve reference %s: %s",
2384 - orig_refname, strerror(errno));
2387 + if (last_errno != ENOTDIR ||
2388 + !verify_refname_available(orig_refname, extras, skip,
2389 + get_loose_refs(&ref_cache), err))
2390 + strbuf_addf(err, "unable to resolve reference %s: %s",
2391 + orig_refname, strerror(last_errno));
2392 +
2393 goto error_return;
2394 }
2395 /*
t/t1404-update-ref-df-conflicts.sh
+4 -4
@@ -36,7 +36,7 @@ test_expect_success 'existing loose ref is a simple prefix of new' '
36
37 prefix=refs/1l &&
38 test_update_rejected $prefix "a c e" false "b c/x d" \
39 - "unable to resolve reference $prefix/c/x: Not a directory"
39 + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x$Q"
40
41 '
42
@@ -52,7 +52,7 @@ test_expect_success 'existing loose ref is a deeper prefix of new' '
52
53 prefix=refs/2l &&
54 test_update_rejected $prefix "a c e" false "b c/x/y d" \
55 - "unable to resolve reference $prefix/c/x/y: Not a directory"
55 + "$Q$prefix/c$Q exists; cannot create $Q$prefix/c/x/y$Q"
56
57 '
58
@@ -68,7 +68,7 @@ test_expect_success 'new ref is a simple prefix of existing loose' '
68
69 prefix=refs/3l &&
70 test_update_rejected $prefix "a c/x e" false "b c d" \
71 - "there are still refs under $Q$prefix/c$Q"
71 + "$Q$prefix/c/x$Q exists; cannot create $Q$prefix/c$Q"
72
73 '
74
@@ -84,7 +84,7 @@ test_expect_success 'new ref is a deeper prefix of existing loose' '
84
85 prefix=refs/4l &&
86 test_update_rejected $prefix "a c/x/y e" false "b c d" \
87 - "there are still refs under $Q$prefix/c$Q"
87 + "$Q$prefix/c/x/y$Q exists; cannot create $Q$prefix/c$Q"
88
89 '
90