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

Re: [PATCH 24/34] checkout: reject if the branch is already checked out elsewhere

From
Duy Nguyen <pclouds@gmail.com>
Date
Dec 1, 2014, 10:38 UTC
Message-ID
<20141201103818.GA20429@lanh>
In-Reply-To
<547B5170.6050206@gmail.com>
On Sun, Nov 30, 2014 at 12:18:40PM -0500, Mark Levedahl wrote:
Show 14 quoted lines
> On 11/30/2014 03:24 AM, Nguyễn Thái Ngọc Duy wrote:
> > One branch obviously can't be checked out at two places (but detached
> > heads are ok). Give the user a choice in this case: --detach, -b
> > new-branch, switch branch in the other checkout first or simply 'cd'
> > and continue to work there.
> >
> 
> This seems too restrictive and is not "obvious" to me: I currently use 
> git-new-workdir to have multiple checkouts of the same branch, with no 
> ill effect. While those who do not understand what is going on 
> underneath might be confused by one checkout suddenly showing 
> uncommitted diffs, I don't accept that as a reason to outright prevent 
> such use. I suggest, at the very least, that this behavior be overridden 
> by a --force flag?

Prevention is a strong word. It's more about safety for the mere mortals. It's certainly possible to do something like this patch (--force can't be reused, it already carries some other meaning). Should I add this one in the next (hic) reroll?

-- 8< --
Subject: [PATCH] checkout: add --ignore-other-wortrees
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-checkout.txt |  6 ++++++
 builtin/checkout.c             | 19 +++++++++++--------
 t/t2025-checkout-to.sh         |  7 +++++++
 3 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 0c13825..71d9e4e 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -232,6 +232,12 @@ section of linkgit:git-add[1] to learn how to operate the `--patch` mode.
 	specific files such as HEAD, index... See "MULTIPLE WORKING
 	TREES" section for more information.
 
+--ignore-other-worktrees::
+	`git checkout` refuses when the wanted ref is already checked out
+	by another worktree. This option makes it check the
+	ref out anyway. In other words, the ref is held by more than one
+	worktree.
+
 <branch>::
 	Branch to checkout; if it refers to a branch (i.e., a name that,
 	when prepended with "refs/heads/", is a valid ref), then that
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 953b763..8b2bf20 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -37,6 +37,7 @@ struct checkout_opts {
 	int writeout_stage;
 	int overwrite_ignore;
 	int ignore_skipworktree;
+	int ignore_other_worktrees;
 
 	const char *new_branch;
 	const char *new_branch_force;
@@ -1079,11 +1080,12 @@ static void check_linked_checkouts(struct branch_info *new)
 static int parse_branchname_arg(int argc, const char **argv,
 				int dwim_new_local_branch_ok,
 				struct branch_info *new,
-				struct tree **source_tree,
-				unsigned char rev[20],
-				const char **new_branch,
-				int force_detach)
+				struct checkout_opts *opts,
+				unsigned char rev[20])
 {
+	struct tree **source_tree = &opts->source_tree;
+	const char **new_branch = &opts->new_branch;
+	int force_detach = opts->force_detach;
 	int argcount = 0;
 	unsigned char branch_rev[20];
 	const char *arg;
@@ -1209,7 +1211,8 @@ static int parse_branchname_arg(int argc, const char **argv,
 		int flag;
 		char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
 		if (head_ref &&
-		    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
+		    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
+		    !opts->ignore_other_worktrees)
 			check_linked_checkouts(new);
 		free(head_ref);
 	}
@@ -1340,6 +1343,8 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 				N_("second guess 'git checkout no-such-branch'")),
 		OPT_FILENAME(0, "to", &opts.new_worktree,
 			   N_("check a branch out in a separate working directory")),
+		OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
+			 N_("do not check if another worktree is holding the given ref")),
 		OPT_END(),
 	};
 
@@ -1420,9 +1425,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
 			opts.track == BRANCH_TRACK_UNSPECIFIED &&
 			!opts.new_branch;
 		int n = parse_branchname_arg(argc, argv, dwim_ok,
-					     &new, &opts.source_tree,
-					     rev, &opts.new_branch,
-					     opts.force_detach);
+					     &new, &opts, rev);
 		argv += n;
 		argc -= n;
 	}
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index 915b506..f8e4df4 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -79,6 +79,13 @@ test_expect_success 'die the same branch is already checked out' '
 	)
 '
 
+test_expect_success 'not die the same branch is already checked out' '
+	(
+		cd here &&
+		git checkout --ignore-other-worktrees --to anothernewmaster newmaster
+	)
+'
+
 test_expect_success 'not die on re-checking out current branch' '
 	(
 		cd there &&
-- 
2.2.0.60.gb7b3c64

-- 8< --
Previous: Mark LevedahlNext: Junio C Hamano
Message 27 of 45 in “nd/multiple-work-trees reroll”
  1. 00/34 nd/multiple-work-trees rerollNguyễn Thái Ngọc Duy, Nov 30, 2014
  2. 01/34 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Nov 30, 2014
  3. 02/34 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Nov 30, 2014
  4. 03/34 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Nov 30, 2014
  5. 04/34 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Nov 30, 2014
  6. 05/34 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Nov 30, 2014
  7. 06/34 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Nov 30, 2014
  8. 07/34 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Nov 30, 2014
  9. 08/34 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Nov 30, 2014
  10. 09/34 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Nov 30, 2014
  11. 10/34 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Nov 30, 2014
  12. 11/34 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Nov 30, 2014
  13. 12/34 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Nov 30, 2014
  14. 13/34 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Nov 30, 2014
  15. 14/34 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Nov 30, 2014
  16. 15/34 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Nov 30, 2014
  17. 16/34 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Nov 30, 2014
  18. 17/34 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Nov 30, 2014
  19. 18/34 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Nov 30, 2014
  20. 19/34 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Nov 30, 2014
  21. 20/34 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Nov 30, 2014
  22. 21/34 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Nov 30, 2014
  23. 22/34 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Nov 30, 2014
  24. 23/34 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Nov 30, 2014
  25. 24/34 checkout: reject if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Nov 30, 2014
  26. Mark LevedahlNov 30, 2014
  27. Duy NguyenDec 1, 2014
  28. Junio C HamanoDec 1, 2014
  29. Mark LevedahlDec 2, 2014
  30. Duy NguyenDec 2, 2014
  31. Junio C HamanoDec 2, 2014
  32. Mark LevedahlDec 3, 2014
  33. Duy NguyenDec 3, 2014
  34. Junio C HamanoDec 3, 2014
  35. Duy NguyenDec 2, 2014
  36. 25/34 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Nov 30, 2014
  37. 26/34 gc: style change -- no SP before closing parenthesisNguyễn Thái Ngọc Duy, Nov 30, 2014
  38. 27/34 gc: factor out gc.pruneexpire parsing codeNguyễn Thái Ngọc Duy, Nov 30, 2014
  39. 28/34 gc: support prune --worktreesNguyễn Thái Ngọc Duy, Nov 30, 2014
  40. 29/34 count-objects: report unused files in $GIT_DIR/worktrees/...Nguyễn Thái Ngọc Duy, Nov 30, 2014
  41. 30/34 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Nov 30, 2014
  42. 31/34 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Nov 30, 2014
  43. 32/34 t2025: add a test to make sure grafts is working from a linked checkoutNguyễn Thái Ngọc Duy, Nov 30, 2014
  44. 33/34 checkout: do not fail if target is an empty directoryNguyễn Thái Ngọc Duy, Nov 30, 2014
  45. 34/34 git-common-dir: make "modules/" per-working-directory directoryNguyễn Thái Ngọc Duy, Nov 30, 2014

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.