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

[PATCH v4 1/4] fetch: Protect branches checked out in all worktrees

From
Anders Kaseorg <andersk@mit.edu>
Date
Nov 9, 2021, 03:00 UTC
Message-ID
<20211109030028.2196416-1-andersk@mit.edu>
In-Reply-To
<a25d105a-875b-fa6a-771a-37936779f067@mit.edu>

Refuse to fetch into the currently checked out branch of any working tree, not just the current one.

Fixes this previously reported bug:
https://public-inbox.org/git/cb957174-5e9a-5603-ea9e-ac9b58a2eaad@mathema.de

As a side effect of using find_shared_symref, we’ll also refuse the fetch when we’re on a detached HEAD because we’re rebasing or bisecting on the branch in question. This seems like a sensible change.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 builtin/fetch.c       | 28 ++++++++++++++--------------
 t/t5516-fetch-push.sh | 18 ++++++++++++++++++
 2 files changed, 32 insertions(+), 14 deletions(-)
diff --git a/builtin/fetch.c b/builtin/fetch.c
index f7abbc31ff..0ef2170ef9 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -28,6 +28,7 @@
 #include "promisor-remote.h"
 #include "commit-graph.h"
 #include "shallow.h"
+#include "worktree.h"
 
 #define FORCED_UPDATES_DELAY_WARNING_IN_MS (10 * 1000)
 
@@ -854,7 +855,7 @@ static int update_local_ref(struct ref *ref,
 			    int summary_width)
 {
 	struct commit *current = NULL, *updated;
-	struct branch *current_branch = branch_get(NULL);
+	const struct worktree *wt;
 	const char *pretty_ref = prettify_refname(ref->name);
 	int fast_forward = 0;
 
@@ -868,16 +869,18 @@ static int update_local_ref(struct ref *ref,
 		return 0;
 	}
 
-	if (current_branch &&
-	    !strcmp(ref->name, current_branch->name) &&
-	    !(update_head_ok || is_bare_repository()) &&
+	if (!update_head_ok &&
+	    (wt = find_shared_symref("HEAD", ref->name)) &&
+	    !wt->is_bare &&
 	    !is_null_oid(&ref->old_oid)) {
 		/*
 		 * If this is the head, and it's not okay to update
 		 * the head, and the old value of the head isn't empty...
 		 */
 		format_display(display, '!', _("[rejected]"),
-			       _("can't fetch in current branch"),
+			       wt->is_current ?
+			       _("can't fetch in current branch") :
+			       _("checked out in another worktree"),
 			       remote, pretty_ref, summary_width);
 		return 1;
 	}
@@ -1387,16 +1390,13 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
 
 static void check_not_current_branch(struct ref *ref_map)
 {
-	struct branch *current_branch = branch_get(NULL);
-
-	if (is_bare_repository() || !current_branch)
-		return;
-
+	const struct worktree *wt;
 	for (; ref_map; ref_map = ref_map->next)
-		if (ref_map->peer_ref && !strcmp(current_branch->refname,
-					ref_map->peer_ref->name))
-			die(_("Refusing to fetch into current branch %s "
-			    "of non-bare repository"), current_branch->refname);
+		if (ref_map->peer_ref &&
+		    (wt = find_shared_symref("HEAD", ref_map->peer_ref->name)))
+			die(_("Refusing to fetch into branch '%s' "
+			      "checked out at '%s'"),
+			    ref_map->peer_ref->name, wt->path);
 }
 
 static int truncate_fetch_head(void)
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 8212ca56dc..2c2d6fa6e7 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1771,4 +1771,22 @@ test_expect_success 'denyCurrentBranch and worktrees' '
 	git -C cloned push origin HEAD:new-wt &&
 	test_must_fail git -C cloned push --delete origin new-wt
 '
+
+test_expect_success 'refuse fetch to current branch of worktree' '
+	test_when_finished "git worktree remove --force wt" &&
+	git worktree add wt &&
+	test_commit apple &&
+	test_must_fail git fetch . HEAD:wt &&
+	git fetch -u . HEAD:wt
+'
+
+test_expect_success 'refuse fetch to current branch of bare repository worktree' '
+	test_when_finished "rm -fr bare.git" &&
+	git clone --bare . bare.git &&
+	git -C bare.git worktree add wt &&
+	test_commit banana &&
+	test_must_fail git -C bare.git fetch .. HEAD:wt &&
+	git -C bare.git fetch -u .. HEAD:wt
+'
+
 test_done
-- 
2.33.1
Previous: Anders KaseorgNext: Anders Kaseorg
Message 6 of 34 in “receive-pack: Protect current branch for bare repository worktree”
  1. 2/2 receive-pack: Protect current branch for bare repository worktreeAnders Kaseorg, Nov 8, 2021
  2. Junio C HamanoNov 8, 2021
  3. Junio C HamanoNov 9, 2021
  4. Johannes SchindelinNov 9, 2021
  5. Anders KaseorgNov 9, 2021
  6. 1/4 fetch: Protect branches checked out in all worktreesAnders Kaseorg, Nov 9, 2021
  7. 2/4 receive-pack: Clean dead code from update_worktree()Anders Kaseorg, Nov 9, 2021
  8. Johannes SchindelinNov 9, 2021
  9. Anders KaseorgNov 9, 2021
  10. 3/4 receive-pack: Protect current branch for bare repository worktreeAnders Kaseorg, Nov 9, 2021
  11. Johannes SchindelinNov 9, 2021
  12. Anders KaseorgNov 9, 2021
  13. 1/4 fetch: Protect branches checked out in all worktreesAnders Kaseorg, Nov 9, 2021
  14. 3/4 receive-pack: Protect current branch for bare repository worktreeAnders Kaseorg, Nov 9, 2021
  15. Ævar Arnfjörð BjarmasonNov 10, 2021
  16. 4/4 branch: Protect branches checked out in all worktreesAnders Kaseorg, Nov 9, 2021
  17. Ævar Arnfjörð BjarmasonNov 10, 2021
  18. 2/4 receive-pack: Clean dead code from update_worktree()Anders Kaseorg, Nov 9, 2021
  19. Ævar Arnfjörð BjarmasonNov 10, 2021
  20. Johannes SchindelinNov 10, 2021
  21. Ævar Arnfjörð BjarmasonNov 10, 2021
  22. Johannes SchindelinNov 10, 2021
  23. Junio C HamanoNov 10, 2021
  24. Junio C HamanoNov 11, 2021
  25. Junio C HamanoNov 10, 2021
  26. Anders KaseorgNov 10, 2021
  27. 4/4 branch: Protect branches checked out in all worktreesAnders Kaseorg, Nov 9, 2021
  28. Johannes SchindelinNov 9, 2021
  29. Johannes SchindelinNov 9, 2021
  30. Anders KaseorgNov 9, 2021
  31. Junio C HamanoNov 9, 2021
  32. Junio C HamanoNov 9, 2021
  33. Anders KaseorgNov 9, 2021
  34. Johannes SchindelinNov 9, 2021

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.