git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 23/23] fetch: improve the error messages emitted for conflicting refspecs

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Oct 30, 2013, 05:33 UTC
Message-ID
<1383111192-23780-24-git-send-email-mhagger@alum.mit.edu>
In-Reply-To
<1383111192-23780-1-git-send-email-mhagger@alum.mit.edu>

If we find two refspecs that want to update the same local reference, emit an error message that is more informative based on whether one of the conflicting refspecs is an opportunistic update during a fetch with explicit command-line refspecs. And especially, do not die if an opportunistic reference update conflicts with an express wish of the user; rather, just emit a warning and skip the opportunistic reference update.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 remote.c                   | 25 ++++++++++++++++++++++---
 t/t5536-fetch-conflicts.sh | 14 +++++++++-----
 2 files changed, 31 insertions(+), 8 deletions(-)
diff --git a/remote.c b/remote.c
index 06a0eda..15e6e5e 100644
--- a/remote.c
+++ b/remote.c
@@ -747,9 +747,28 @@ int for_each_remote(each_remote_fn fn, void *priv)
 
 static void handle_duplicate(struct ref *ref1, struct ref *ref2)
 {
-	if (strcmp(ref1->name, ref2->name))
-		die(_("%s tracks both %s and %s"),
-		    ref2->peer_ref->name, ref1->name, ref2->name);
+	if (strcmp(ref1->name, ref2->name)) {
+		if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+		    ref2->fetch_head_status != FETCH_HEAD_IGNORE) {
+			die(_("Cannot fetch both %s and %s to %s"),
+			    ref1->name, ref2->name, ref2->peer_ref->name);
+		} else if (ref1->fetch_head_status != FETCH_HEAD_IGNORE &&
+			   ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+			warning(_("%s usually tracks %s, not %s"),
+				ref2->peer_ref->name, ref2->name, ref1->name);
+		} else if (ref1->fetch_head_status == FETCH_HEAD_IGNORE &&
+			   ref2->fetch_head_status == FETCH_HEAD_IGNORE) {
+			die(_("%s tracks both %s and %s"),
+			    ref2->peer_ref->name, ref1->name, ref2->name);
+		} else {
+			/*
+			 * This last possibility doesn't occur because
+			 * FETCH_HEAD_IGNORE entries always appear at
+			 * the end of the list.
+			 */
+			die(_("Internal error"));
+		}
+	}
 	free(ref2->peer_ref);
 	free(ref2);
 }
diff --git a/t/t5536-fetch-conflicts.sh b/t/t5536-fetch-conflicts.sh
index 679c53e..6c5d3a4 100755
--- a/t/t5536-fetch-conflicts.sh
+++ b/t/t5536-fetch-conflicts.sh
@@ -22,7 +22,7 @@ verify_stderr () {
 	cat >expected &&
 	# We're not interested in the error
 	# "fatal: The remote end hung up unexpectedly":
-	grep -v "hung up" <error >actual &&
+	grep -E '^(fatal|warning):' <error | grep -v 'hung up' >actual | sort &&
 	test_cmp expected actual
 }
 
@@ -49,7 +49,7 @@ test_expect_success 'fetch conflict: config vs. config' '
 		cd ccc &&
 		test_must_fail git fetch origin 2>error &&
 		verify_stderr <<-\EOF
-		fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2
+		fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1
 		EOF
 	)
 '
@@ -78,18 +78,22 @@ test_expect_success 'fetch conflict: arg vs. arg' '
 			refs/heads/*:refs/remotes/origin/* \
 			refs/heads/branch2:refs/remotes/origin/branch1 2>error &&
 		verify_stderr <<-\EOF
-		fatal: refs/remotes/origin/branch1 tracks both refs/heads/branch1 and refs/heads/branch2
+		fatal: Cannot fetch both refs/heads/branch1 and refs/heads/branch2 to refs/remotes/origin/branch1
 		EOF
 	)
 '
 
-test_expect_failure 'fetch conflict: criss-cross args' '
+test_expect_success 'fetch conflict: criss-cross args' '
 	setup_repository xaa \
 		"+refs/heads/*:refs/remotes/origin/*" && (
 		cd xaa &&
 		git fetch origin \
 			refs/heads/branch1:refs/remotes/origin/branch2 \
-			refs/heads/branch2:refs/remotes/origin/branch1
+			refs/heads/branch2:refs/remotes/origin/branch1 2>error &&
+		verify_stderr <<-\EOF
+		warning: refs/remotes/origin/branch1 usually tracks refs/heads/branch1, not refs/heads/branch2
+		warning: refs/remotes/origin/branch2 usually tracks refs/heads/branch2, not refs/heads/branch1
+		EOF
 	)
 '
 
-- 
1.8.4.1
Previous: Michael Haggerty
Message 28 of 28 in “Change semantics of "fetch --tags"”
  1. 00/23 Change semantics of "fetch --tags"Michael Haggerty, Oct 30, 2013
  2. 01/23 t5510: use the correct tag name in testMichael Haggerty, Oct 30, 2013
  3. 02/23 t5510: prepare test refs more straightforwardlyMichael Haggerty, Oct 30, 2013
  4. Ramkumar RamachandraOct 30, 2013
  5. Michael HaggertyOct 30, 2013
  6. 03/23 t5510: check that "git fetch --prune --tags" does not prune branchesMichael Haggerty, Oct 30, 2013
  7. 04/23 api-remote.txt: correct section "struct refspec"Michael Haggerty, Oct 30, 2013
  8. 05/23 get_ref_map(): rename local variablesMichael Haggerty, Oct 30, 2013
  9. 06/23 builtin/fetch.c: reorder function definitionsMichael Haggerty, Oct 30, 2013
  10. 07/23 get_expanded_map(): add docstringMichael Haggerty, Oct 30, 2013
  11. 08/23 get_expanded_map(): avoid memory leakMichael Haggerty, Oct 30, 2013
  12. 09/23 fetch: only opportunistically update references based on command lineMichael Haggerty, Oct 30, 2013
  13. 10/23 fetch --tags: fetch tags *in addition to* other stuffMichael Haggerty, Oct 30, 2013
  14. 11/23 fetch --prune: prune only based on explicit refspecsMichael Haggerty, Oct 30, 2013
  15. 12/23 query_refspecs(): move some constants out of the loopMichael Haggerty, Oct 30, 2013
  16. Ramkumar RamachandraOct 30, 2013
  17. Michael HaggertyOct 30, 2013
  18. 13/23 builtin/remote.c: reorder function definitionsMichael Haggerty, Oct 30, 2013
  19. 14/23 builtin/remote.c:update(): use struct argv_arrayMichael Haggerty, Oct 30, 2013
  20. 15/23 fetch, remote: properly convey --no-prune options to subprocessesMichael Haggerty, Oct 30, 2013
  21. 16/23 fetch-options.txt: simplify ifdef/ifndef/endif usageMichael Haggerty, Oct 30, 2013
  22. 17/23 git-fetch.txt: improve description of tag auto-followingMichael Haggerty, Oct 30, 2013
  23. 18/23 ref_remove_duplicates(): avoid redundant bisectionMichael Haggerty, Oct 30, 2013
  24. 19/23 t5536: new test of refspec conflicts when fetchingMichael Haggerty, Oct 30, 2013
  25. 20/23 ref_remove_duplicates(): simplify loop logicMichael Haggerty, Oct 30, 2013
  26. 21/23 ref_remote_duplicates(): extract a function handle_duplicate()Michael Haggerty, Oct 30, 2013
  27. 22/23 handle_duplicate(): mark error message for translationMichael Haggerty, Oct 30, 2013
  28. 23/23 fetch: improve the error messages emitted for conflicting refspecsMichael Haggerty, Oct 30, 2013

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.