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

[PATCH] worktree: teach find_shared_symref to ignore current worktree

From
Rubén Justo <rjusto@gmail.com>
Date
Jan 17, 2023, 00:36 UTC
Message-ID
<eeb0c778-af0a-235c-f009-bca3abafdb15@gmail.com>

We prevent some operations from being executed on a branch checked out in a worktree other than the current one. An example of this was introduced in b5cabb4 (rebase: refuse to switch to branch already checked out elsewhere, 2020-02-23).

"find_shared_symref()" is sometimes used to find the worktree in which a branch is checked out. It performs its search starting with the current worktree.

As we allow to have the same branch checked out in multiple worktrees simultaneously...

	$ git worktree add foo
	$ git worktree add -f bar foo
	$ git checkout --ignore-other-worktrees foo

... if the branch checked out in the current worktree is also checked out in another worktree, with "find_shared_symref()" we will not notice this "other" working tree.

Let's teach "find_shared_symref()" to ignore the current worktree in the search, based on the caller's needs.

Signed-off-by: Rubén Justo <rjusto@gmail.com>
---
 branch.c               | 4 ++--
 builtin/notes.c        | 2 +-
 builtin/receive-pack.c | 2 +-
 t/t3400-rebase.sh      | 3 +++
 worktree.c             | 6 +++++-
 worktree.h             | 3 ++-
 6 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/branch.c b/branch.c
index d182756827..2508e94add 100644
--- a/branch.c
+++ b/branch.c
@@ -822,8 +822,8 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
 	struct worktree **worktrees = get_worktrees();
 	const struct worktree *wt;
 
-	wt = find_shared_symref(worktrees, "HEAD", branch);
-	if (wt && (!ignore_current_worktree || !wt->is_current)) {
+	wt = find_shared_symref(worktrees, "HEAD", branch, ignore_current_worktree);
+	if (wt) {
 		skip_prefix(branch, "refs/heads/", &branch);
 		die(_("'%s' is already checked out at '%s'"), branch, wt->path);
 	}
diff --git a/builtin/notes.c b/builtin/notes.c
index 80d9dfd25c..80326bdaab 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -869,7 +869,7 @@ static int merge(int argc, const char **argv, const char *prefix)
 		/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
 		worktrees = get_worktrees();
 		wt = find_shared_symref(worktrees, "NOTES_MERGE_REF",
-					default_notes_ref());
+					default_notes_ref(), 0);
 		if (wt)
 			die(_("a notes merge into %s is already in-progress at %s"),
 			    default_notes_ref(), wt->path);
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index a90af30363..18d400101c 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1460,7 +1460,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 	int do_update_worktree = 0;
 	struct worktree **worktrees = get_worktrees();
 	const struct worktree *worktree =
-		find_shared_symref(worktrees, "HEAD", name);
+		find_shared_symref(worktrees, "HEAD", name, 0);
 
 	/* only refs/... are allowed */
 	if (!starts_with(name, "refs/") || check_refname_format(name + 5, 0)) {
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index d5a8ee39fc..874cfff8fe 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -407,6 +407,9 @@ test_expect_success 'refuse to switch to branch checked out elsewhere' '
 	git checkout main &&
 	git worktree add wt &&
 	test_must_fail git -C wt rebase main main 2>err &&
+	test_i18ngrep "already checked out" err &&
+	git worktree add --force wt2 main &&
+	test_must_fail git rebase main main &&
 	test_i18ngrep "already checked out" err
 '
 
diff --git a/worktree.c b/worktree.c
index aa43c64119..3d686137ef 100644
--- a/worktree.c
+++ b/worktree.c
@@ -405,7 +405,8 @@ int is_worktree_being_bisected(const struct worktree *wt,
  */
 const struct worktree *find_shared_symref(struct worktree **worktrees,
 					  const char *symref,
-					  const char *target)
+					  const char *target,
+					  int ignore_current_worktree)
 {
 	const struct worktree *existing = NULL;
 	int i = 0;
@@ -416,6 +417,9 @@ const struct worktree *find_shared_symref(struct worktree **worktrees,
 		struct ref_store *refs;
 		int flags;
 
+		if (wt->is_current && ignore_current_worktree)
+			continue;
+
 		if (wt->is_bare)
 			continue;
 
diff --git a/worktree.h b/worktree.h
index 9dcea6fc8c..a9f35ee990 100644
--- a/worktree.h
+++ b/worktree.h
@@ -147,7 +147,8 @@ void free_worktrees(struct worktree **);
  */
 const struct worktree *find_shared_symref(struct worktree **worktrees,
 					  const char *symref,
-					  const char *target);
+					  const char *target,
+					  int ignore_current_worktree);
 
 /*
  * Similar to head_ref() for all HEADs _except_ one from the current
-- 
2.39.0
Next: Junio C Hamano
Message 1 of 40 in “worktree: teach find_shared_symref to ignore current worktree”
  1. worktree: teach find_shared_symref to ignore current worktreeRubén Justo, Jan 17, 2023
  2. Junio C HamanoJan 17, 2023
  3. Rubén JustoJan 18, 2023
  4. Phillip WoodJan 19, 2023
  5. Rubén JustoJan 19, 2023
  6. 0/3 fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Jan 22, 2023
  7. 1/3 branch: fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Jan 22, 2023
  8. Junio C HamanoJan 22, 2023
  9. Rubén JustoJan 22, 2023
  10. Junio C HamanoJan 22, 2023
  11. Rubén JustoJan 22, 2023
  12. Phillip WoodJan 24, 2023
  13. Rubén JustoJan 26, 2023
  14. 2/3 rebase: refuse to switch to a branch already checked out elsewhere (test)Rubén Justo, Jan 22, 2023
  15. 3/3 switch: reject if the branch is already checked out elsewhere (test)Rubén Justo, Jan 22, 2023
  16. 0/4 fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Feb 4, 2023
  17. 1/4 worktree: introduce is_shared_symref()Rubén Justo, Feb 4, 2023
  18. Phillip WoodFeb 7, 2023
  19. 2/4 branch: fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Feb 4, 2023
  20. Ævar Arnfjörð BjarmasonFeb 6, 2023
  21. Rubén JustoFeb 6, 2023
  22. Phillip WoodFeb 7, 2023
  23. Ævar Arnfjörð BjarmasonFeb 7, 2023
  24. 3/4 rebase: refuse to switch to a branch already checked out elsewhere (test)Rubén Justo, Feb 4, 2023
  25. Ævar Arnfjörð BjarmasonFeb 6, 2023
  26. Rubén JustoFeb 6, 2023
  27. Phillip WoodFeb 7, 2023
  28. Rubén JustoFeb 8, 2023
  29. Junio C HamanoFeb 8, 2023
  30. Rubén JustoFeb 8, 2023
  31. 4/4 switch: reject if the branch is already checked out elsewhere (test)Rubén Justo, Feb 4, 2023
  32. Eric SunshineFeb 15, 2023
  33. Rubén JustoFeb 15, 2023
  34. 0/4 fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Feb 25, 2023
  35. 1/4 worktree: introduce is_shared_symref()Rubén Justo, Feb 25, 2023
  36. 2/4 branch: fix die_if_checked_out() when ignore_current_worktreeRubén Justo, Feb 25, 2023
  37. 3/4 rebase: refuse to switch to a branch already checked out elsewhere (test)Rubén Justo, Feb 25, 2023
  38. 4/4 switch: reject if the branch is already checked out elsewhere (test)Rubén Justo, Feb 25, 2023
  39. Junio C HamanoFeb 25, 2023
  40. Rubén JustoFeb 27, 2023

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.