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

[PATCH 2/2] remote: handle rename of remote without fetch refspec

From
Jeff King <peff@peff.net>
Date
Sep 22, 2022, 05:33 UTC
Message-ID
<YyvzqZ5tmI0UdRAW@coredump.intra.peff.net>
In-Reply-To
<YyvzIQL9H9aTYNch@coredump.intra.peff.net>

We return an error when trying to rename a remote that has no fetch refspec:

  $ git config --unset-all remote.origin.fetch
  $ git remote rename origin foo
  fatal: could not unset 'remote.foo.fetch'

To make things even more confusing, we actually _do_ complete the config modification, via git_config_rename_section(). After that we try to rewrite the fetch refspec (to say refs/remotes/foo instead of origin). But our call to git_config_set_multivar() to remove the existing entries fails, since there aren't any, and it calls die().

We could fix this by using the "gently" form of the config call, and checking the error code. But there is an even simpler fix: if we know that there are no refspecs to rewrite, then we can skip that part entirely.

Reported-by: John A. Leuenhagen <john@zlima12.com>
Signed-off-by: Jeff King <peff@peff.net>
---
The diff is a bit noisy due to indentation, but with "-w" you can see
that it's just wrapping this part of the function in a conditional.
 builtin/remote.c  | 48 ++++++++++++++++++++++++-----------------------
 t/t5505-remote.sh | 11 +++++++++++
 2 files changed, 36 insertions(+), 23 deletions(-)
diff --git a/builtin/remote.c b/builtin/remote.c
index 985b845a18..910f7b9316 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -733,29 +733,31 @@ static int mv(int argc, const char **argv, const char *prefix)
 		return error(_("Could not rename config section '%s' to '%s'"),
 				buf.buf, buf2.buf);
 
-	strbuf_reset(&buf);
-	strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
-	git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
-	strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
-	for (i = 0; i < oldremote->fetch.raw_nr; i++) {
-		char *ptr;
-
-		strbuf_reset(&buf2);
-		strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
-		ptr = strstr(buf2.buf, old_remote_context.buf);
-		if (ptr) {
-			refspec_updated = 1;
-			strbuf_splice(&buf2,
-				      ptr-buf2.buf + strlen(":refs/remotes/"),
-				      strlen(rename.old_name), rename.new_name,
-				      strlen(rename.new_name));
-		} else
-			warning(_("Not updating non-default fetch refspec\n"
-				  "\t%s\n"
-				  "\tPlease update the configuration manually if necessary."),
-				buf2.buf);
-
-		git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+	if (oldremote->fetch.raw_nr) {
+		strbuf_reset(&buf);
+		strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
+		git_config_set_multivar(buf.buf, NULL, NULL, CONFIG_FLAGS_MULTI_REPLACE);
+		strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
+		for (i = 0; i < oldremote->fetch.raw_nr; i++) {
+			char *ptr;
+
+			strbuf_reset(&buf2);
+			strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
+			ptr = strstr(buf2.buf, old_remote_context.buf);
+			if (ptr) {
+				refspec_updated = 1;
+				strbuf_splice(&buf2,
+					      ptr-buf2.buf + strlen(":refs/remotes/"),
+					      strlen(rename.old_name), rename.new_name,
+					      strlen(rename.new_name));
+			} else
+				warning(_("Not updating non-default fetch refspec\n"
+					  "\t%s\n"
+					  "\tPlease update the configuration manually if necessary."),
+					buf2.buf);
+
+			git_config_set_multivar(buf.buf, buf2.buf, "^$", 0);
+		}
 	}
 
 	read_branches();
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 9006196ac6..43b7bcd715 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -902,6 +902,17 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but keeps g
 	)
 '
 
+test_expect_success 'rename handles remote without fetch refspec' '
+	git clone --bare one no-refspec.git &&
+	# confirm assumption that bare clone does not create refspec
+	test_expect_code 5 \
+		git -C no-refspec.git config --unset-all remote.origin.fetch &&
+	git -C no-refspec.git config remote.origin.url >expect &&
+	git -C no-refspec.git remote rename origin foo &&
+	git -C no-refspec.git config remote.foo.url >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'rename does not update a non-default fetch refspec' '
 	git clone one four.one &&
 	(
-- 
2.38.0.rc1.580.gfaa349ad1e
Previous: Jeff King
Message 11 of 11 in “fatal: options '--bare' and '--origin foo' cannot be used together”
  1. John A. LeuenhagenSep 21, 2022
  2. Jeff KingSep 22, 2022
  3. Jeff KingSep 22, 2022
  4. 1/2 clone: allow "--bare" with "-o"Jeff King, Sep 22, 2022
  5. Eric SunshineSep 22, 2022
  6. Jeff KingSep 22, 2022
  7. Eric SunshineSep 22, 2022
  8. Jeff KingSep 22, 2022
  9. Eric SunshineSep 22, 2022
  10. Jeff KingSep 22, 2022
  11. 2/2 remote: handle rename of remote without fetch refspecJeff King, Sep 22, 2022

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.