threads / patch / 64143

patch, 3 partsextend --ignore-other-worktrees to 'rebase', add hints

Subject: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints

## tl;dr

20 messages between Sep 13, 2025 and Sep 19, 2025. Diffs are folded; open one to read it.

replies: 19people: 5as markdown or json

Gabriel Scherer· Sep 13, 2025, 14:13 UTC · lore

The old 'workdir' contribution script was removed from git upstream in May 2025, as it is largely superseded by the 'worktree' command.

One significant difference between the old script and the command is that 'git' refuses to checkout or rebase branches that are already checked out in another worktree. My understanding of the reasoning is that users may be surprised when a clean worktree becomes dirty as its index is changed from another worktree. However, this safety net adds a mental burden to worktree users, as they have to keep the other worktrees in mind when moving branches. Old goats like me who are used to the old 'workdir' script find this restriction somewhat painful.

See the discussion thread
  https://lore.kernel.org/git/5580aa89-09f1-426e-8483-c99481c998ab@gmail.com/
about this transition.

The present patch series tries to provide a smoother migration path for supporters of worktree independence:

 - when 'checkout' refuses because the branch is used in another worktree,
   display a 'hint' that mentions the possibility of using '--detach'
   instead, and the '--ignore-other-worktrees' option to proceed anyway.
 - add support for '--ignore-other-worktrees' in 'rebase' as well, with
   a similar hint.

In the future I would be interested in adding an option 'branch.ignoreOtherWorktrees' to be able to ignore other worktrees globally.

Note: this is my first experience submitting a patch to the Git project, so
I apologize in advance for any mishap and welcome beginner-level feedback.
Cc: Junio C Hamano <gitster@pobox.com>
Cc: D. Ben Knoble <ben.knoble@gmail.com>
Cc: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
Gabriel.Scherer (3):
  checkout: provide hint when failing due to another worktree
  rebase: support --ignore-other-worktrees
  rebase: hint when failing on branch used by another worktree
 Documentation/config/advice.adoc |  3 +++
 Documentation/git-rebase.adoc    |  6 ++++++
 advice.c                         |  1 +
 advice.h                         |  1 +
 branch.c                         | 13 +++++++++++--
 branch.h                         |  4 ++++
 builtin/checkout.c               | 12 ++++++++++--
 builtin/rebase.c                 | 19 ++++++++++++++++++-
 t/t3400-rebase.sh                |  4 +++-
 9 files changed, 57 insertions(+), 6 deletions(-)
-- 
2.51.0
Gabriel Scherer· Sep 13, 2025, 14:13 UTC · re: Gabriel Scherer · lore

[PATCH 1/3] checkout: provide hint when failing due to another worktree

From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>

When checkout/switch fails because the target branch is already used by another worktree, we now hint that the user could use --detach or --ignore-other-worktrees.

Note: this error can also happen on rebase, which unfortunately does
not support --ignore-other-worktrees. We do not show advice in this
case, and leave 'rebase --ignore-other-worktrees' to future work.
Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
---
 Documentation/config/advice.adoc |  3 +++
 advice.c                         |  1 +
 advice.h                         |  1 +
 branch.c                         | 13 +++++++++++--
 branch.h                         |  4 ++++
 builtin/checkout.c               | 12 ++++++++++--
 6 files changed, 30 insertions(+), 4 deletions(-)
Show changes to 6 files +30 −4

Documentation/config/advice.adoc, advice.c, advice.h, branch.c, branch.h, builtin/checkout.c

diff --git a/Documentation/config/advice.adoc b/Documentation/config/advice.adoc
index 257db58918..9ee64f44ea 100644
--- a/Documentation/config/advice.adoc
+++ b/Documentation/config/advice.adoc
@@ -27,6 +27,9 @@ all advice messages.
 		Shown when a fetch refspec for multiple remotes maps to
 		the same remote-tracking branch namespace and causes branch
 		tracking set-up to fail.
+	branchUsedInOtherWorktree::
+		Shown when the user attemps to switch to a branch
+		that is already checked out in another worktree.
 	checkoutAmbiguousRemoteBranchName::
 		Shown when the argument to
 		linkgit:git-checkout[1] and linkgit:git-switch[1]
diff --git a/advice.c b/advice.c
index e5f0ff8449..5c9b763472 100644
--- a/advice.c
+++ b/advice.c
@@ -50,6 +50,7 @@ static struct {
 	[ADVICE_AMBIGUOUS_FETCH_REFSPEC]		= { "ambiguousFetchRefspec" },
 	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir" },
 	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName" },
+	[ADVICE_BRANCH_USED_IN_OTHER_WORKTREE]		= { "branchUsedInOtherWorktree" },
 	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge" },
 	[ADVICE_DEFAULT_BRANCH_NAME]			= { "defaultBranchName" },
 	[ADVICE_DETACHED_HEAD]				= { "detachedHead" },
diff --git a/advice.h b/advice.h
index 727dcecf4a..6b11df945b 100644
--- a/advice.h
+++ b/advice.h
@@ -16,6 +16,7 @@ enum advice_type {
 	ADVICE_ADD_IGNORED_FILE,
 	ADVICE_AMBIGUOUS_FETCH_REFSPEC,
 	ADVICE_AM_WORK_DIR,
+	ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
 	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
 	ADVICE_COMMIT_BEFORE_MERGE,
 	ADVICE_DEFAULT_BRANCH_NAME,
diff --git a/branch.c b/branch.c
index 26be358347..76aa2cbf44 100644
--- a/branch.c
+++ b/branch.c
@@ -844,7 +844,7 @@ void remove_branch_state(struct repository *r, int verbose)
 	remove_merge_branch_state(r);
 }
 
-void die_if_checked_out(const char *branch, int ignore_current_worktree)
+int die_message_if_checked_out(const char *branch, int ignore_current_worktree)
 {
 	struct worktree **worktrees = get_worktrees();
 
@@ -854,10 +854,19 @@ void die_if_checked_out(const char *branch, int ignore_current_worktree)
 
 		if (is_shared_symref(worktrees[i], "HEAD", branch)) {
 			skip_prefix(branch, "refs/heads/", &branch);
-			die(_("'%s' is already used by worktree at '%s'"),
+			return die_message(
+				_("'%s' is already used by worktree at '%s'"),
 				branch, worktrees[i]->path);
 		}
 	}
 
 	free_worktrees(worktrees);
+	return 0;
+}
+
+void die_if_checked_out(const char *branch, int ignore_current_worktree)
+{
+	int code = die_message_if_checked_out(branch, ignore_current_worktree);
+	if (code)
+		exit(code);
 }
diff --git a/branch.h b/branch.h
index ec2f35fda4..84c81508e9 100644
--- a/branch.h
+++ b/branch.h
@@ -155,4 +155,8 @@ int read_branch_desc(struct strbuf *, const char *branch_name);
  */
 void die_if_checked_out(const char *branch, int ignore_current_worktree);
 
+/* Similar to 'die_if_checked_out' above, but returns a non-zero
+   error code after printing the message instead of dying immediately. */
+int die_message_if_checked_out(const char *branch, int ignore_current_worktree);
+
 #endif
diff --git a/builtin/checkout.c b/builtin/checkout.c
index f9453473fe..e4b78f4a05 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -1582,8 +1582,16 @@ static void die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
 		return;
 	head_ref = refs_resolve_refdup(get_main_ref_store(the_repository),
 				       "HEAD", 0, NULL, &flags);
-	if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref)))
-		die_if_checked_out(full_ref, 1);
+	if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref, full_ref))) {
+		int code = die_message_if_checked_out(full_ref, 1);
+		if (code) {
+			advise_if_enabled(
+				ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
+				_("Use --detach to avoid this restriction,\n"
+				"or --ignore-other-worktrees to ignore it."));
+			exit(code);
+		}
+	}
 	free(head_ref);
 }
 
-- 
2.51.0
Kristoffer Haugsbakk· Sep 13, 2025, 20:55 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Unrelated: I found it confusing that my `co = checkout` alias did not
work with this fresh-off-the-press Advice:[1]

``` $ ./git co master fatal: 'master' is already used by worktree at '<path>' $ ./git checkout master fatal: 'master' is already used by worktree at '<patch>' hint: Use --detach to avoid this restriction, hint: or --ignore-other-worktrees to ignore it. hint: Disable this message with "git config set advice.branchUsedInOtherWorktree false" ```

But it did for this older Advice (which is in my installed git(1)):

``` $ ./git co -b .. @ fatal: '..' is not a valid branch name hint: See `man git check-ref-format` hint: Disable this message with "git config set advice.refSyntax false" ```

It’s because aliases are run as a subprocess from the `git` in `PATH`:

``` strvec_push(&cmd.args, "git"); ```

[1]: Chain of events:
1. Try to trigger the Advice in this series
2. ... but it doesn’t
3. Is the code wrong?
4. Wait, I’m using my alias (which I always use; I don’t think about it)
5. I test with `git checkout`: it works
6. ... so aliases don’t work with Advice?
7. Test an existing Advice that I know about
8. ... but it does work with aliases
9.–15. ...
It was part of the process.  I didn’t *decide* to get hung up on it. ;)
On Sat, Sep 13, 2025, at 16:13, Gabriel Scherer wrote:
Show 5 quoted lines
> From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>
>
> When checkout/switch fails because the target branch is already used
> by another worktree, we now hint that the user could use --detach or
> --ignore-other-worktrees.

The commit message is supposed to discuss what the code does without the patch in the present tense. What the patch does is in the imperative mood. Refer to `Documentation/SubmittingPatches`, “imperative mood”.

Maybe there should be a paragraph which motivates the need for an Advice and these two in particular? You could also concievably advise removing the worktree. :)

> Note: this error can also happen on rebase, which unfortunately does
> not support --ignore-other-worktrees. We do not show advice in this
> case, and leave 'rebase --ignore-other-worktrees' to future work.

After reading this I thought this was not handled by this patch series. But you add the this option to git-rebase(1) in the second patch.

“Future work” suggests to me something ranging from:

• there is another patch series that deal with this; or • there are no plans to do this (but it could be done in theory).

Show 23 quoted lines
>
> Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
> ---
>  Documentation/config/advice.adoc |  3 +++
>  advice.c                         |  1 +
>  advice.h                         |  1 +
>  branch.c                         | 13 +++++++++++--
>  branch.h                         |  4 ++++
>  builtin/checkout.c               | 12 ++++++++++--
>  6 files changed, 30 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/config/advice.adoc
> b/Documentation/config/advice.adoc
> index 257db58918..9ee64f44ea 100644
> --- a/Documentation/config/advice.adoc
> +++ b/Documentation/config/advice.adoc
> @@ -27,6 +27,9 @@ all advice messages.
>  		Shown when a fetch refspec for multiple remotes maps to
>  		the same remote-tracking branch namespace and causes branch
>  		tracking set-up to fail.
> +	branchUsedInOtherWorktree::
> +		Shown when the user attemps to switch to a branch
> +		that is already checked out in another worktree.

This maintains sort-order which is good. It is also consistent in all points with 95c987e6fad (advice: make all entries stylistically consistent, 2024-03-05) for what it’s worth.

I also think the wording/formulation is great.
Show 12 quoted lines
>  	checkoutAmbiguousRemoteBranchName::
>  		Shown when the argument to
>  		linkgit:git-checkout[1] and linkgit:git-switch[1]
> diff --git a/advice.c b/advice.c
> index e5f0ff8449..5c9b763472 100644
> --- a/advice.c
> +++ b/advice.c
> @@ -50,6 +50,7 @@ static struct {
>  	[ADVICE_AMBIGUOUS_FETCH_REFSPEC]		= { "ambiguousFetchRefspec" },
>  	[ADVICE_AM_WORK_DIR] 				= { "amWorkDir" },
>  	[ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME] 	= { "checkoutAmbiguousRemoteBranchName" },
> +	[ADVICE_BRANCH_USED_IN_OTHER_WORKTREE]		= { "branchUsedInOtherWorktree" },

This too looks like it should be in sort order. If so you are inserting at the wrong place.

Show 12 quoted lines
>  	[ADVICE_COMMIT_BEFORE_MERGE]			= { "commitBeforeMerge" },
>  	[ADVICE_DEFAULT_BRANCH_NAME]			= { "defaultBranchName" },
>  	[ADVICE_DETACHED_HEAD]				= { "detachedHead" },
> diff --git a/advice.h b/advice.h
> index 727dcecf4a..6b11df945b 100644
> --- a/advice.h
> +++ b/advice.h
> @@ -16,6 +16,7 @@ enum advice_type {
>  	ADVICE_ADD_IGNORED_FILE,
>  	ADVICE_AMBIGUOUS_FETCH_REFSPEC,
>  	ADVICE_AM_WORK_DIR,
> +	ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
Correct sort order (if there is one).
Show 32 quoted lines
>  	ADVICE_CHECKOUT_AMBIGUOUS_REMOTE_BRANCH_NAME,
>  	ADVICE_COMMIT_BEFORE_MERGE,
>  	ADVICE_DEFAULT_BRANCH_NAME,
> diff --git a/branch.c b/branch.c
> index 26be358347..76aa2cbf44 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -844,7 +844,7 @@ void remove_branch_state(struct repository *r, int
> verbose)
>  	remove_merge_branch_state(r);
>  }
>[snip diff]
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index f9453473fe..e4b78f4a05 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -1582,8 +1582,16 @@ static void
> die_if_switching_to_a_branch_in_use(struct checkout_opts *opts,
>  		return;
>  	head_ref = refs_resolve_refdup(get_main_ref_store(the_repository),
>  				       "HEAD", 0, NULL, &flags);
> -	if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref,
> full_ref)))
> -		die_if_checked_out(full_ref, 1);
> +	if (head_ref && (!(flags & REF_ISSYMREF) || strcmp(head_ref,
> full_ref))) {
> +		int code = die_message_if_checked_out(full_ref, 1);
> +		if (code) {
> +			advise_if_enabled(
> +				ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
> +				_("Use --detach to avoid this restriction,\n"
> +				"or --ignore-other-worktrees to ignore it."));

I don’t know if `--detach` will “avoid” the restriction. (In fact `--ignore-other-worktrees` might be the one that *avoids* it (turns it off)?)

Technically the only point of being-on-a-branch is to be able to advance it. You know that. But does the advice-receiver? Because they might use the hint to get what they want immediately. Then later wonder why all the work they did on the branch “had no effect”.

Show 8 quoted lines
> +			exit(code);
> +		}
> +	}
>  	free(head_ref);
>  }
>
> --
> 2.51.0
No updates to tests were covered in another email.
-- 
Kristoffer Haugsbakk
Gabriel Scherer· Sep 14, 2025, 07:50 UTC · re: Kristoffer Haugsbakk · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Thanks for your feedback -- I fixed the sort order, and will try to reword the commit description as suggested.

On 13/09/2025 22:55, Kristoffer Haugsbakk wrote:
Show 13 quoted lines
>> +			advise_if_enabled(
>> +				ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
>> +				_("Use --detach to avoid this restriction,\n"
>> +				"or --ignore-other-worktrees to ignore it."));
> 
> I don’t know if `--detach` will “avoid” the restriction.  (In fact
> `--ignore-other-worktrees` might be the one that *avoids* it (turns it
> off)?)
> 
> Technically the only point of being-on-a-branch is to be able to advance
> it.  You know that.  But does the advice-receiver?  Because they might
> use the hint to get what they want immediately.  Then later wonder why
> all the work they did on the branch “had no effect”.
In my in-progress version of the patch, the reworded advice is as follows:

fatal: 'foo' is already used by worktree at '/home/gasche/Prog/foo' hint: If you want to proceed anyway, try again with --ignore-other-worktrees. hint: Changes to the branch will also impact the other worktrees. hint: hint: If you want to detach HEAD at that branch, try again with the --detach option.

(The last part is shown when ADVICE_SUGGEST_DETACHING_HEAD is enabled, and reuses the existing wording for that advice.)

Junio C Hamano· Sep 15, 2025, 08:53 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Gabriel Scherer <gabriel.scherer@inria.fr> writes:
Show 9 quoted lines
> In my in-progress version of the patch, the reworded advice is as follows:
>
> fatal: 'foo' is already used by worktree at '/home/gasche/Prog/foo'
> hint: If you want to proceed anyway, try again with
> --ignore-other-worktrees.
> hint: Changes to the branch will also impact the other worktrees.
> hint:
> hint: If you want to detach HEAD at that branch, try again with the
> --detach option.

To those who _need_ these hint messages (in other words, those who cannot choose the right way to do what they wanted to do without getting hints), I suspect think "if you want to proceed anyway", "impact" and "if you want to" are not concrete enough to help them make the right choices.

"If you want to proceed anyway"---of course they all do, because they do not know what risks they are taking, and this message does not tell them about. So that isn't very helpful message.

Changes to the branch would not change the index or any files in the working tree of other worktree, leading these users to think that they safely live in two separte isolated worlds in these two separate worktrees. Is it clear to them that the "impact" you are talking about is exactly the fact that these changes are *NOT* propagated to other worktree?

Then you have "if you want to" without telling the readers why they should "want to" (or not) detach. Which is not all that helpful. Why should I go into the scary sounding "detached HEAD" mode? For what for? If a user can answer that question themselves, they do not even need that hint.

I think the message should help the readers eventually realize the following things to make intelligent decisions. Making them short to fit in the "hint:" messages is left as an exercise ;-)

 - 'foo' is already in use and in which worktree.  Your message
   "fatal:" is very clear and is good.
 - if you checkout 'foo' here and start growing or otherwise
   updating the history of 'foo' in this worktree, the index and the
   working tree files of other worktree(s) will go out of sync with
   the tip of 'foo'.  if they 'git commit' from that state, for
   example, it is very likely that they will record a change that
   reverts your changes from the history of 'foo', and you do not
   want that.
 - if you want to grow history of 'foo' in potentially different
   direction from what the other worktree with 'foo' is working on,
   you are better off creating a separte branch 'foo2', with
   anticipation that you'll eventually merge them together.
 - if you only want to browse the files or build but have no
   intention to change the files or make commits, then you can have
   the HEAD of this working tree detached at the commit at the tip
   of 'foo'.  An advantage of this approach is that it will keep you
   honest, if you know that you are *not* on 'foo', but not on any
   branch, it would discourage you from making commits and
   disturbing the other working tree.  Another advantage is that
   when you do need to make commits (perhaps while you are browsing
   the files, you may find small typos you want to fix), you can at
   that time run "git checkout -b foo-typofix" to create a new
   branch and commit, without disturbing the other worktree that
   have 'foo' checked out.
Gabriel Scherer· Sep 15, 2025, 19:52 UTC · re: Junio C Hamano · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Thanks for the detailed comments!
On 15/09/2025 10:53, Junio C Hamano wrote:
Show 34 quoted lines
> Gabriel Scherer <gabriel.scherer@inria.fr> writes:
> 
>> In my in-progress version of the patch, the reworded advice is as follows:
>>
>> fatal: 'foo' is already used by worktree at '/home/gasche/Prog/foo'
>> hint: If you want to proceed anyway, try again with
>> --ignore-other-worktrees.
>> hint: Changes to the branch will also impact the other worktrees.
>> hint:
>> hint: If you want to detach HEAD at that branch, try again with the
>> --detach option.
> 
> To those who _need_ these hint messages (in other words, those who
> cannot choose the right way to do what they wanted to do without
> getting hints), I suspect think "if you want to proceed anyway",
> "impact" and "if you want to" are not concrete enough to help them
> make the right choices.
> 
> "If you want to proceed anyway"---of course they all do, because
> they do not know what risks they are taking, and this message does
> not tell them about.  So that isn't very helpful message.
> 
> Changes to the branch would not change the index or any files in the
> working tree of other worktree, leading these users to think that
> they safely live in two separte isolated worlds in these two
> separate worktrees.  Is it clear to them that the "impact" you are
> talking about is exactly the fact that these changes are *NOT*
> propagated to other worktree?
> 
> Then you have "if you want to" without telling the readers why they
> should "want to" (or not) detach.  Which is not all that helpful.
> Why should I go into the scary sounding "detached HEAD" mode?  For
> what for?  If a user can answer that question themselves, they do
> not even need that hint.
To my defense, this is the hint wording that is already in the git codebase:
   $ git switch HEAD~3
   fatal: a branch is expected, got commit 'HEAD~3'
   hint: If you want to detach HEAD at the commit, try again with the 
--detach option.

I am happy to improve this wording as well if we can converge to concrete recommendations.

> I think the message should help the readers eventually realize the
> following things to make intelligent decisions.  Making them short
> to fit in the "hint:" messages is left as an exercise ;-)

Hints make advanced features self-discoverable -- otherwise we find them out by reading the entire doc of a command when we are stuck After reading the hint, users can read the documentation in a more targeted way to understand the implications.

Would referring the user to the documentation be acceptable?

For 'detach' hints, there is a detailed section DETACHED HEAD in the 'checkout' documentation, which the hint could refer to. For example (imaginary output):

   $ git checkout HEAD~3fatal: a branch is expected, got commit 'HEAD~3'
   hint: If you want to detach HEAD at the commit, try again with the 
--detach option.
   hint: See the "DETACHED HEAD" section in the 'git checkout' 
documentation.

On the other hand for --ignore-other-worktrees there is no user-friendly documentation of these questions currently (I looked at the 'worktree' documentation, in particular for the --force option, and at the --ignore-other-worktrees documentation for 'checkout').

If you agree in principle, I can update my patchset with a documentation commit that explains the justification for the worktree restriction, what happens if we ignore this restriction, and what is the recommended way to respect it.

Show 10 quoted lines
>   - 'foo' is already in use and in which worktree.  Your message
>     "fatal:" is very clear and is good.
> 
>   - if you checkout 'foo' here and start growing or otherwise
>     updating the history of 'foo' in this worktree, the index and the
>     working tree files of other worktree(s) will go out of sync with
>     the tip of 'foo'.  if they 'git commit' from that state, for
>     example, it is very likely that they will record a change that
>     reverts your changes from the history of 'foo', and you do not
>     want that.

(This gets me to wonder if a desirable behavior could be to 'detach' the other worktrees that had the same branch checked out, instead of failing on checkout. Users starting to use the other worktree again would possibly notice more quickly that something is amiss.)

For me this situation is not a big deal: if they commit the removal of 'foo', presumably they will notice that the diff/changes in their commit is not what they expect, and they can come back to the previous state.

I agree that this is surprising and I understand why the project decided to discourage this by default ('fatal error' is plenty discouraging), but there is no data loss or anything of the sort, only recoverable surprises.

>   - if you want to grow history of 'foo' in potentially different
>     direction from what the other worktree with 'foo' is working on,
>     you are better off creating a separte branch 'foo2', with
>     anticipation that you'll eventually merge them together.
Use-case examples:
1. my colleague has a long-lived feature branch called 'super-feature'
2. last year I did a lot of review work on their branch in a separate 
worktree which is still somewhere on my filesystem, but which I am not 
actively working on anymore (and maybe never will)
3. I am in the middle of a bugfix session in another worktree, and 
suddenly I want to check if the bug also occurs in 'super-feature'; I 
stash my current stuff, checkout 'super-feature', and run 'git pull' to 
update it to match my colleague's remote to get the most recent version 
and test it against this bug.

In this scenario, I don't want my current work in (3) to be interrupted by the fact that an old worktree (2) exists that also tracks super-feature, and in fact I do want to update my local 'super-feature' branch to the most recent version. Maybe later on I will come back to my old super-feature worktree (but maybe in another year), and I will start with a 'git pull' or some other command, and I will quickly realize that its index is out of date and fix it.

Show 12 quoted lines
>   - if you only want to browse the files or build but have no
>     intention to change the files or make commits, then you can have
>     the HEAD of this working tree detached at the commit at the tip
>     of 'foo'.  An advantage of this approach is that it will keep you
>     honest, if you know that you are *not* on 'foo', but not on any
>     branch, it would discourage you from making commits and
>     disturbing the other working tree.  Another advantage is that
>     when you do need to make commits (perhaps while you are browsing
>     the files, you may find small typos you want to fix), you can at
>     that time run "git checkout -b foo-typofix" to create a new
>     branch and commit, without disturbing the other worktree that
>     have 'foo' checked out.

I agree that detached-head is a reasonable point in the design space in some cases, so I think that it is reasonable to hint about both options. I am happy to put the detach advice first if this has your preference.

(Note: In the earlier mailing-list thread I discarded detached HEAD because its default rendering in the git bash prompt is unpleasant, it shows the commit and does not mention the detached branch name anymore, which is disorienting. I have since realized that there is a non-default setting GIT_PS1_DESCRIBE_STYLE=branch that can be used to see say "((trunk))" in that case (when we are detached on top of a "trunk" branch, which makes it much more pleasant to use.)

Junio C Hamano· Sep 16, 2025, 05:32 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Gabriel Scherer <gabriel.scherer@inria.fr> writes:
> On the other hand for --ignore-other-worktrees there is no
> user-friendly documentation of these questions currently (I looked at
> the 'worktree' documentation, in particular for the --force option,
> and at the --ignore-other-worktrees documentation for 'checkout').

Oh, that's bad and we should improve them, regardless of what we say in the hints.

> restriction, what happens if we ignore this restriction, and what is
> the recommended way to respect it.
Sounds good.
Show 14 quoted lines
>>   - 'foo' is already in use and in which worktree.  Your message
>>     "fatal:" is very clear and is good.
>>   - if you checkout 'foo' here and start growing or otherwise
>>     updating the history of 'foo' in this worktree, the index and the
>>     working tree files of other worktree(s) will go out of sync with
>>     the tip of 'foo'.  if they 'git commit' from that state, for
>>     example, it is very likely that they will record a change that
>>     reverts your changes from the history of 'foo', and you do not
>>     want that.
>
> (This gets me to wonder if a desirable behavior could be to 'detach'
> the other worktrees that had the same branch checked out, instead of
> failing on checkout. Users starting to use the other worktree again
> would possibly notice more quickly that something is amiss.)

I generally advise against pulling the rug under somebody else's feet. You do not know what that other worktree is used for, or if somebody is using it right now making changes and whatnot. What happens in the worktree that the end-user has just issued the command you are executing is much more controllable.

Show 9 quoted lines
> For me this situation is not a big deal: if they commit the removal of
> 'foo', presumably they will notice that the diff/changes in their
> commit is not what they expect, and they can come back to the previous
> state.
>
> I agree that this is surprising and I understand why the project
> decided to discourage this by default ('fatal error' is plenty
> discouraging), but there is no data loss or anything of the sort, only
> recoverable surprises.

The question is how would they, the person who worked on the other working tree that first checked out 'foo' and perhaps worked for some time with local modifications, and then left the worktree so long ago that they forgot that they have a checkout of it (and that is why they just got told by "git checkout" that there _is_ another worktree that checks out 'foo' already exists), _find_ where the previous state is in the first place, once they go back to the other worktree. You may be nice and have advanced the branch by only one or two commits, and they may be able to find where they were by going back a few entries in "git log" output. But you may rebase the branch and the place where they started from in the other worktree may no longer exist. Then what? It does not sounds like a recoverable surprise to me at all.

Show 25 quoted lines
>>   - if you want to grow history of 'foo' in potentially different
>>     direction from what the other worktree with 'foo' is working on,
>>     you are better off creating a separte branch 'foo2', with
>>     anticipation that you'll eventually merge them together.
>
> Use-case examples:
>
> 1. my colleague has a long-lived feature branch called 'super-feature'
> 2. last year I did a lot of review work on their branch in a separate
> worktree which is still somewhere on my filesystem, but which I am not
> actively working on anymore (and maybe never will)
> 3. I am in the middle of a bugfix session in another worktree, and
> suddenly I want to check if the bug also occurs in 'super-feature'; I
> stash my current stuff, checkout 'super-feature', and run 'git pull'
> to update it to match my colleague's remote to get the most recent
> version and test it against this bug.
>
> In this scenario, I don't want my current work in (3) to be
> interrupted by the fact that an old worktree (2) exists that also
> tracks super-feature, and in fact I do want to update my local
> 'super-feature' branch to the most recent version.
> Maybe later on I will come back to my old super-feature worktree (but
> maybe in another year), and I will start with a 'git pull' or some
> other command, and I will quickly realize that its index is out of
> date and fix it.

If #3 involved only "checkout" of super-feature to build and test, then detached HEAD is the perfect tool that was designed to be used in such a situation. But if the goal is you want to have _his_ latest super-feature expanded in your filesystem so that you can build and debug, you do not want to checkout super-feature and pull, which WILL move your super-feature branch and make #1 worktree useless. They may have made quite a lot of changes, and your previous state, the state you were reviewing (and perhaps you had a few of your own fixup patches there) may not even be reachable from their updated tip of the super-feature branch.

If I were in that situation in step #3, I'll probably do
 $ git stash save -m 'in the middle of a bugfix session'
 $ git fetch his super-feature
 $ git checkout --detach his/super-feature
Junio C Hamano· Sep 17, 2025, 14:17 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Gabriel Scherer <gabriel.scherer@inria.fr> writes:
Show 9 quoted lines
> To my defense, this is the hint wording that is already in the git codebase:
>
>   $ git switch HEAD~3
>   fatal: a branch is expected, got commit 'HEAD~3'
>   hint: If you want to detach HEAD at the commit, try again with the
>   --detach option.
>
> I am happy to improve this wording as well if we can converge to
> concrete recommendations.
This looks like a typical apples-and-oranges comparison to me.

I do not see any need to improve the above. In this case, it is clear that the user did want to detach but they just forgot that the "switch" comand wants an explicit "--detach" [*] when switching into a detached HEAD state. There is nothing inherently risky in the act of detaching HEAD that makes it something to be discouraged.

    Side note: This was deliberately made to behave differently from
    the "checkout" command, which intelligently did the right thing
    without being told, i.e. HEAD~3 cannot be a branch name, hence
    it took the command line "git checkout HEAD~3" as an obvious
    request to detach HEAD at that commit.  So if the user came from
    knowing "checkout", it is an easy mistake to make when they
    switch to "switch".  No pun intended.

This is vastly different from trying to checkout a branch and then it turns out that the branch is already in use in somewhere else. We strongly and actively discourage a branch from being used in two different places, in order to avoid an update to it from one place breaking the other place. Unlike detaching HEAD, this one is something the user needs to think twice before doing so.

And in such a request, there is no indication that the user even knew that the branch was already in use elsewhere. It is plausible that the user may not even have tried to check it out if they knew it is checked out elsewhere beforehand (if simply because such a request would be rejected by the safety mechanism); if they only wanted to peek, and if they knew there is already a checkout, they may have just cd'ed there to peek, for example.

Depending on what they wanted to do by having a checkout of that branch, a suitable and safe course of action would be different, and hints would want to help them make right decisions among various possibilities.

Show 9 quoted lines
>> I think the message should help the readers eventually realize the
>> following things to make intelligent decisions.  Making them short
>> to fit in the "hint:" messages is left as an exercise ;-)
>
> Hints make advanced features self-discoverable -- otherwise we find
> them out by reading the entire doc of a command when we are stuck
>
> After reading the hint, users can read the documentation in a more
> targeted way to understand the implications.

Sure. I phrased the above paragraph is somewhat awkwardly, but the point I wanted to convey was that the message would never be able to teach everything they need to know---rather it should give a good starting point and pointers to lead them in the right directions to find out what the best course of action for their situation.

> Would referring the user to the documentation be acceptable?

So, yes. I think risks need to be told in the message to make them realize that blindly proceeding with a hammer without understanding consequence is not a good idea, but we do not need to be exhausive in listing what tools other than the hammer are available, and the hint message would not have enough room to be a manual. So a loud warning of risks, and a couple of pointers into the documentation, would be very much appropriate, I would think.

Thanks.
Gabriel Scherer· Sep 17, 2025, 15:25 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Dear git developers,
On 15/09/2025 21:52, Gabriel Scherer wrote:
> (This gets me to wonder if a desirable behavior could be to 'detach' the other worktrees that had the same branch checked out, instead of failing on checkout. Users starting to use the other worktree again would possibly notice more quickly that something is amiss.)

After the new feedback from Junio, I wonder if I should explore this suggestion more actively.

For now my goal has been to make --ignore-other-worktrees more discoverable, for people who are willing to take the risk. (I am comfortable doing this as I have used this workflow for years without much trouble with the 'workdir' script, but clearly you want to be very careful in how exactly we suggest that it is a possibility.)

Would you prefer a different option to detach the branch at the other 
worktrees? This could be
   git checkout --detach-other-worktrees <branch>
for example.

I did not originally consider this as it requires more expertise in git internal data structures, but it may be easier than finding a way to advertise --ignore-other-worktrees that you are really comfortable with.

Phillip Wood· Sep 19, 2025, 14:13 UTC · re: Gabriel Scherer · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Hi Gabriel
On 17/09/2025 16:25, Gabriel Scherer wrote:
Show 21 quoted lines
> Dear git developers,
> 
> On 15/09/2025 21:52, Gabriel Scherer wrote:
>> (This gets me to wonder if a desirable behavior could be to 'detach' 
>> the other worktrees that had the same branch checked out, instead of 
>> failing on checkout. Users starting to use the other worktree again 
>> would possibly notice more quickly that something is amiss.)
> 
> After the new feedback from Junio, I wonder if I should explore this 
> suggestion more actively.
> 
> For now my goal has been to make --ignore-other-worktrees more 
> discoverable, for people who are willing to take the risk. (I am 
> comfortable doing this as I have used this workflow for years without 
> much trouble with the 'workdir' script, but clearly you want to be very 
> careful in how exactly we suggest that it is a possibility.)
> 
> Would you prefer a different option to detach the branch at the other 
> worktrees? This could be
>    git checkout --detach-other-worktrees <branch>
> for example.

In general we try to avoid having commands run in one worktree affect a checkout in another worktree so I'm not sure we'd really want to go that route.

> I did not originally consider this as it requires more expertise in git 
> internal data structures, but it may be easier than finding a way to 
> advertise --ignore-other-worktrees that you are really comfortable with.

I think it comes down to the same problem that we're not that comfortable with the idea of having the same branch checked out in multiple worktrees. I'd have though having some advice that suggests using --detach should be relatively uncontroversial. Suggesting "--ignore-other-worktrees" would certainly require some kind of warning. If it is hard to come up with a concise hint maybe we could have an expanded discussion in the documentation and have the hint refer to that?

Thanks
Phillip
Ben Knoble· Sep 14, 2025, 19:03 UTC · re: Kristoffer Haugsbakk · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Show 43 quoted lines
> Le 13 sept. 2025 à 16:56, Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com> a écrit :
> 
> Unrelated: I found it confusing that my `co = checkout` alias did not
> work with this fresh-off-the-press Advice:[1]
> 
> ```
> $ ./git co master
> fatal: 'master' is already used by worktree at '<path>'
> $ ./git checkout master
> fatal: 'master' is already used by worktree at '<patch>'
> hint: Use --detach to avoid this restriction,
> hint: or --ignore-other-worktrees to ignore it.
> hint: Disable this message with "git config set advice.branchUsedInOtherWorktree false"
> ```
> 
> But it did for this older Advice (which is in my installed git(1)):
> 
> ```
> $ ./git co -b .. @
> fatal: '..' is not a valid branch name
> hint: See `man git check-ref-format`
> hint: Disable this message with "git config set advice.refSyntax false"
> ```
> 
> It’s because aliases are run as a subprocess from the `git` in `PATH`:
> 
> ```
> strvec_push(&cmd.args, "git");
> ```
> 
> [1]: Chain of events:
> 
> 1. Try to trigger the Advice in this series
> 2. ... but it doesn’t
> 3. Is the code wrong?
> 4. Wait, I’m using my alias (which I always use; I don’t think about it)
> 5. I test with `git checkout`: it works
> 6. ... so aliases don’t work with Advice?
> 7. Test an existing Advice that I know about
> 8. ... but it does work with aliases
> 9.–15. ...
> 
> It was part of the process.  I didn’t *decide* to get hung up on it. ;)
Using bin-wrappers/git should set things up correctly, I think?
Ben Knoble· Sep 14, 2025, 19:06 UTC · re: Ben Knoble · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

Show 48 quoted lines
> Le 14 sept. 2025 à 15:03, Ben Knoble <ben.knoble@gmail.com> a écrit :
> 
> 
>> Le 13 sept. 2025 à 16:56, Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com> a écrit :
>> 
>> Unrelated: I found it confusing that my `co = checkout` alias did not
>> work with this fresh-off-the-press Advice:[1]
>> 
>> ```
>> $ ./git co master
>> fatal: 'master' is already used by worktree at '<path>'
>> $ ./git checkout master
>> fatal: 'master' is already used by worktree at '<patch>'
>> hint: Use --detach to avoid this restriction,
>> hint: or --ignore-other-worktrees to ignore it.
>> hint: Disable this message with "git config set advice.branchUsedInOtherWorktree false"
>> ```
>> 
>> But it did for this older Advice (which is in my installed git(1)):
>> 
>> ```
>> $ ./git co -b .. @
>> fatal: '..' is not a valid branch name
>> hint: See `man git check-ref-format`
>> hint: Disable this message with "git config set advice.refSyntax false"
>> ```
>> 
>> It’s because aliases are run as a subprocess from the `git` in `PATH`:
>> 
>> ```
>> strvec_push(&cmd.args, "git");
>> ```
>> 
>> [1]: Chain of events:
>> 
>> 1. Try to trigger the Advice in this series
>> 2. ... but it doesn’t
>> 3. Is the code wrong?
>> 4. Wait, I’m using my alias (which I always use; I don’t think about it)
>> 5. I test with `git checkout`: it works
>> 6. ... so aliases don’t work with Advice?
>> 7. Test an existing Advice that I know about
>> 8. ... but it does work with aliases
>> 9.–15. ...
>> 
>> It was part of the process.  I didn’t *decide* to get hung up on it. ;)
> 
> Using bin-wrappers/git should set things up correctly, I think?
Ok, just saw the other patch series and see how this could not work. Thanks. 
Kristoffer Haugsbakk· Sep 14, 2025, 19:32 UTC · re: Ben Knoble · lore

Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree

On Sun, Sep 14, 2025, at 21:03, Ben Knoble wrote:
>>[snip]
>> It was part of the process.  I didn’t *decide* to get hung up on it. ;)
>
> Using bin-wrappers/git should set things up correctly, I think?
That does work for me.  Thanks.
Gabriel Scherer· Sep 13, 2025, 14:13 UTC · re: Gabriel Scherer · lore

[PATCH 2/3] rebase: support --ignore-other-worktrees

From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>

rebase can currently fail if the branch to rebase is checked out in another worktree, and there is no way for users to override this error. We add support for the '--ignore-other-worktrees' option of 'checkout'.

Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
---
 Documentation/git-rebase.adoc |  6 ++++++
 builtin/rebase.c              | 11 ++++++++++-
 t/t3400-rebase.sh             |  4 +++-
 3 files changed, 19 insertions(+), 2 deletions(-)
Show changes to 3 files +19 −2

Documentation/git-rebase.adoc, builtin/rebase.c, t/t3400-rebase.sh

diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
index 005caf6164..b703d4056e 100644
--- a/Documentation/git-rebase.adoc
+++ b/Documentation/git-rebase.adoc
@@ -305,6 +305,12 @@ see the `--empty` flag.
 +
 See also INCOMPATIBLE OPTIONS below.
 
+--ignore-other-worktrees::
+	By default, `git rebase` refuses when the branch to rebase is
+	already checked out or otherwise in use by another
+	worktree. With this option, other worktrees are ignored and
+	the rebase proceeds anyway.
+
 --reapply-cherry-picks::
 --no-reapply-cherry-picks::
 	Reapply all clean cherry-picks of any upstream commit instead
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 3c85768d29..7a57ebd852 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -128,6 +128,7 @@ struct rebase_options {
 	struct strbuf git_format_patch_opt;
 	int reschedule_failed_exec;
 	int reapply_cherry_picks;
+	int ignore_other_worktrees;
 	int fork_point;
 	int update_refs;
 	int config_autosquash;
@@ -146,6 +147,7 @@ struct rebase_options {
 		.git_format_patch_opt = STRBUF_INIT,	\
 		.fork_point = -1,			\
 		.reapply_cherry_picks = -1,             \
+		.ignore_other_worktrees = -1,           \
 		.allow_empty_message = 1,               \
 		.autosquash = -1,                       \
 		.rebase_merges = -1,                    \
@@ -1234,6 +1236,8 @@ int cmd_rebase(int argc,
 			 N_("automatically re-schedule any `exec` that fails")),
 		OPT_BOOL(0, "reapply-cherry-picks", &options.reapply_cherry_picks,
 			 N_("apply all changes, even those already present upstream")),
+		OPT_BOOL(0, "ignore-other-worktrees", &options.ignore_other_worktrees,
+			 N_("do not check if another worktree is using the branch to rebase")),
 		OPT_END(),
 	};
 	int i;
@@ -1580,6 +1584,10 @@ int cmd_rebase(int argc,
 			(options.flags & REBASE_INTERACTIVE_EXPLICIT);
 	}
 
+	if (options.ignore_other_worktrees == -1) {
+		options.ignore_other_worktrees = 0;
+	}
+
 	if (options.type == REBASE_UNSPECIFIED) {
 		if (!strcmp(options.default_backend, "merge"))
 			options.type = REBASE_MERGE;
@@ -1679,7 +1687,8 @@ int cmd_rebase(int argc,
 		strbuf_reset(&buf);
 		strbuf_addf(&buf, "refs/heads/%s", branch_name);
 		if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
-			die_if_checked_out(buf.buf, 1);
+			if (!options.ignore_other_worktrees)
+				die_if_checked_out(buf.buf, 1);
 			options.head_name = xstrdup(buf.buf);
 			options.orig_head =
 				lookup_commit_object(the_repository,
diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
index c0c00fbb7b..08448b4d4e 100755
--- a/t/t3400-rebase.sh
+++ b/t/t3400-rebase.sh
@@ -407,7 +407,9 @@ test_expect_success 'switch to branch checked out elsewhere fails' '
 	# we test in both worktrees to ensure that works
 	# as expected with "first" and "next" worktrees
 	test_must_fail git -C wt1 rebase shared shared &&
-	test_must_fail git -C wt2 rebase shared shared
+	test_must_fail git -C wt2 rebase shared shared &&
+        # with --ignore-other-worktrees the rebase succeeds
+	git -C wt1 rebase --ignore-other-worktrees shared shared
 '
 
 test_expect_success 'switch to branch not checked out' '
-- 
2.51.0
Phillip Wood· Sep 15, 2025, 10:09 UTC · re: Gabriel Scherer · lore

Re: [PATCH 2/3] rebase: support --ignore-other-worktrees

Hi Gabriel
On 13/09/2025 15:13, Gabriel Scherer wrote:
Show 6 quoted lines
> From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>
> 
> rebase can currently fail if the branch to rebase is checked out in
> another worktree, and there is no way for users to override this
> error. We add support for the '--ignore-other-worktrees' option of
> 'checkout'.

I'm not sure we want to be encouraging users to rebase a branch that is already checked out in another worktree. Unlike the checkout case where they maybe just reading the code and not updating the branch, rebase will update the branch which is going to be confusing. We could, perhaps, add a hint suggesting that if they are making experimental changes, they might want to rebase a detached HEAD instead with

     git rebase <upstream> <branch>^0

but I'm not sure if that is helpful or if using a detached HEAD will just confuse users.

Thanks
Phillip
Show 89 quoted lines
> Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
> ---
>   Documentation/git-rebase.adoc |  6 ++++++
>   builtin/rebase.c              | 11 ++++++++++-
>   t/t3400-rebase.sh             |  4 +++-
>   3 files changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/Documentation/git-rebase.adoc b/Documentation/git-rebase.adoc
> index 005caf6164..b703d4056e 100644
> --- a/Documentation/git-rebase.adoc
> +++ b/Documentation/git-rebase.adoc
> @@ -305,6 +305,12 @@ see the `--empty` flag.
>   +
>   See also INCOMPATIBLE OPTIONS below.
>   
> +--ignore-other-worktrees::
> +	By default, `git rebase` refuses when the branch to rebase is
> +	already checked out or otherwise in use by another
> +	worktree. With this option, other worktrees are ignored and
> +	the rebase proceeds anyway.
> +
>   --reapply-cherry-picks::
>   --no-reapply-cherry-picks::
>   	Reapply all clean cherry-picks of any upstream commit instead
> diff --git a/builtin/rebase.c b/builtin/rebase.c
> index 3c85768d29..7a57ebd852 100644
> --- a/builtin/rebase.c
> +++ b/builtin/rebase.c
> @@ -128,6 +128,7 @@ struct rebase_options {
>   	struct strbuf git_format_patch_opt;
>   	int reschedule_failed_exec;
>   	int reapply_cherry_picks;
> +	int ignore_other_worktrees;
>   	int fork_point;
>   	int update_refs;
>   	int config_autosquash;
> @@ -146,6 +147,7 @@ struct rebase_options {
>   		.git_format_patch_opt = STRBUF_INIT,	\
>   		.fork_point = -1,			\
>   		.reapply_cherry_picks = -1,             \
> +		.ignore_other_worktrees = -1,           \
>   		.allow_empty_message = 1,               \
>   		.autosquash = -1,                       \
>   		.rebase_merges = -1,                    \
> @@ -1234,6 +1236,8 @@ int cmd_rebase(int argc,
>   			 N_("automatically re-schedule any `exec` that fails")),
>   		OPT_BOOL(0, "reapply-cherry-picks", &options.reapply_cherry_picks,
>   			 N_("apply all changes, even those already present upstream")),
> +		OPT_BOOL(0, "ignore-other-worktrees", &options.ignore_other_worktrees,
> +			 N_("do not check if another worktree is using the branch to rebase")),
>   		OPT_END(),
>   	};
>   	int i;
> @@ -1580,6 +1584,10 @@ int cmd_rebase(int argc,
>   			(options.flags & REBASE_INTERACTIVE_EXPLICIT);
>   	}
>   
> +	if (options.ignore_other_worktrees == -1) {
> +		options.ignore_other_worktrees = 0;
> +	}
> +
>   	if (options.type == REBASE_UNSPECIFIED) {
>   		if (!strcmp(options.default_backend, "merge"))
>   			options.type = REBASE_MERGE;
> @@ -1679,7 +1687,8 @@ int cmd_rebase(int argc,
>   		strbuf_reset(&buf);
>   		strbuf_addf(&buf, "refs/heads/%s", branch_name);
>   		if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
> -			die_if_checked_out(buf.buf, 1);
> +			if (!options.ignore_other_worktrees)
> +				die_if_checked_out(buf.buf, 1);
>   			options.head_name = xstrdup(buf.buf);
>   			options.orig_head =
>   				lookup_commit_object(the_repository,
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index c0c00fbb7b..08448b4d4e 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -407,7 +407,9 @@ test_expect_success 'switch to branch checked out elsewhere fails' '
>   	# we test in both worktrees to ensure that works
>   	# as expected with "first" and "next" worktrees
>   	test_must_fail git -C wt1 rebase shared shared &&
> -	test_must_fail git -C wt2 rebase shared shared
> +	test_must_fail git -C wt2 rebase shared shared &&
> +        # with --ignore-other-worktrees the rebase succeeds
> +	git -C wt1 rebase --ignore-other-worktrees shared shared
>   '
>   
>   test_expect_success 'switch to branch not checked out' '
Junio C Hamano· Sep 15, 2025, 16:23 UTC · re: Phillip Wood · lore

Re: [PATCH 2/3] rebase: support --ignore-other-worktrees

Phillip Wood <phillip.wood123@gmail.com> writes:
Show 21 quoted lines
> Hi Gabriel
>
> On 13/09/2025 15:13, Gabriel Scherer wrote:
>> From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>
>> rebase can currently fail if the branch to rebase is checked out in
>> another worktree, and there is no way for users to override this
>> error. We add support for the '--ignore-other-worktrees' option of
>> 'checkout'.
>
> I'm not sure we want to be encouraging users to rebase a branch that
> is already checked out in another worktree. Unlike the checkout case
> where they maybe just reading the code and not updating the branch,
> rebase will update the branch which is going to be confusing. We
> could, perhaps, add a hint suggesting that if they are making
> experimental changes, they might want to rebase a detached HEAD
> instead with
>
>     git rebase <upstream> <branch>^0
>
> but I'm not sure if that is helpful or if using a detached HEAD will
> just confuse users.

The risk of confusion is real in a workflow like this. Hinting them to go to that existing worktree that is used to checkout that branch and rebasing it there might be less risky.

But stepping back a bit, if the user reader wants to rebase the branch in this worktree, instead of in the other worktree, is because they has uncommitted changes in the worktree that already checks out the branch, the branch may not even be ready to be rebased?

Thanks.
Gabriel Scherer· Sep 13, 2025, 14:13 UTC · re: Gabriel Scherer · lore

[PATCH 3/3] rebase: hint when failing on branch used by another worktree

From: "Gabriel.Scherer" <gabriel.scherer@inria.fr>
Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
---
 builtin/rebase.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
Show changes to builtin/rebase.c +10 −2
diff --git a/builtin/rebase.c b/builtin/rebase.c
index 7a57ebd852..05c86117fc 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -9,6 +9,7 @@
 
 #include "builtin.h"
 
+#include "advice.h"
 #include "abspath.h"
 #include "environment.h"
 #include "gettext.h"
@@ -1687,8 +1688,15 @@ int cmd_rebase(int argc,
 		strbuf_reset(&buf);
 		strbuf_addf(&buf, "refs/heads/%s", branch_name);
 		if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) {
-			if (!options.ignore_other_worktrees)
-				die_if_checked_out(buf.buf, 1);
+			if (!options.ignore_other_worktrees) {
+				int code = die_message_if_checked_out(buf.buf, 1);
+				if (code) {
+					advise_if_enabled(
+						ADVICE_BRANCH_USED_IN_OTHER_WORKTREE,
+						_("Use --ignore-other-worktrees to proceed anyway."));
+					exit(code);
+				}
+			}
 			options.head_name = xstrdup(buf.buf);
 			options.orig_head =
 				lookup_commit_object(the_repository,
-- 
2.51.0
Ben Knoble· Sep 13, 2025, 19:30 UTC · re: Gabriel Scherer · lore

Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints

Show 33 quoted lines
> Le 13 sept. 2025 à 10:13, Gabriel Scherer <gabriel.scherer@inria.fr> a écrit :
> 
> The old 'workdir' contribution script was removed from git upstream in May
> 2025, as it is largely superseded by the 'worktree' command.
> 
> One significant difference between the old script and the command is that
> 'git' refuses to checkout or rebase branches that are already checked out in
> another worktree. My understanding of the reasoning is that users may be
> surprised when a clean worktree becomes dirty as its index is changed from
> another worktree. However, this safety net adds a mental burden to worktree
> users, as they have to keep the other worktrees in mind when moving
> branches. Old goats like me who are used to the old 'workdir' script find
> this restriction somewhat painful.
> 
> See the discussion thread
>  https://lore.kernel.org/git/5580aa89-09f1-426e-8483-c99481c998ab@gmail.com/
> about this transition.
> 
> The present patch series tries to provide a smoother migration path for
> supporters of worktree independence:
> 
> - when 'checkout' refuses because the branch is used in another worktree,
>   display a 'hint' that mentions the possibility of using '--detach'
>   instead, and the '--ignore-other-worktrees' option to proceed anyway.
> 
> - add support for '--ignore-other-worktrees' in 'rebase' as well, with
>   a similar hint.
> 
> In the future I would be interested in adding an option
> 'branch.ignoreOtherWorktrees' to be able to ignore other worktrees globally.
> 
> Note: this is my first experience submitting a patch to the Git project, so
> I apologize in advance for any mishap and welcome beginner-level feedback.
I’m eager to see further reviews, but nothing I saw in this series stuck out as a major problem. I saw we updated the rebase test cases; should we add some more for checkout or worktree?
Gabriel Scherer· Sep 13, 2025, 20:02 UTC · re: Ben Knoble · lore

Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints

Thanks for looking!
On 13/09/2025 21:30, Ben Knoble wrote:
> I’m eager to see further reviews, but nothing I saw in this series stuck out as a major problem. I saw we updated the rebase test cases; should we add some more for checkout or worktree?

There is already a check of the --ignore-other-worktrees option for 'checkout' in t/t2060-switch.sh. The test only records success or failure, not hints; but I checked manually that the hints are shown as expected.

There are code paths in 'worktree add' that call the same die_if_checked_out function, but I did not touch those. They seem to support the --force option to disable the check, and we could also have a hint to make this self-discoverable. (One could suggest also having a --ignore-other-worktrees option in 'worktree' for consistency, but unlike 'checkout' the --force option currently has no additional effect than ignoring other worktrees.) Please let me know if you think that some changes to worktree.c should be included in the present patchset for consistency.

Phillip Wood· Sep 15, 2025, 10:09 UTC · re: Gabriel Scherer · lore

Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints

Hi Gabriel
On 13/09/2025 15:13, Gabriel Scherer wrote:
Show 22 quoted lines
> The old 'workdir' contribution script was removed from git upstream in May
> 2025, as it is largely superseded by the 'worktree' command.
> 
> One significant difference between the old script and the command is that
> 'git' refuses to checkout or rebase branches that are already checked out in
> another worktree. My understanding of the reasoning is that users may be
> surprised when a clean worktree becomes dirty as its index is changed from
> another worktree. However, this safety net adds a mental burden to worktree
> users, as they have to keep the other worktrees in mind when moving
> branches. Old goats like me who are used to the old 'workdir' script find
> this restriction somewhat painful.
> 
> See the discussion thread
>    https://lore.kernel.org/git/5580aa89-09f1-426e-8483-c99481c998ab@gmail.com/
> about this transition.
> 
> The present patch series tries to provide a smoother migration path for
> supporters of worktree independence:
> 
>   - when 'checkout' refuses because the branch is used in another worktree,
>     display a 'hint' that mentions the possibility of using '--detach'
>     instead, and the '--ignore-other-worktrees' option to proceed anyway.

I think this is a good idea, though I agree with Junio that we want the hint to be a bit more explicit about where using --detach or --ignore-other-worktrees are appropriate.

>   - add support for '--ignore-other-worktrees' in 'rebase' as well, with
>     a similar hint.

I'm less convinced this is a good idea as the rebase command updates the branch which is going to be confusing if the branch is checked out elsewhere.

Thanks
Phillip
Show 28 quoted lines
> In the future I would be interested in adding an option
> 'branch.ignoreOtherWorktrees' to be able to ignore other worktrees globally.
> 
> Note: this is my first experience submitting a patch to the Git project, so
> I apologize in advance for any mishap and welcome beginner-level feedback.
> 
> Cc: Junio C Hamano <gitster@pobox.com>
> Cc: D. Ben Knoble <ben.knoble@gmail.com>
> Cc: Phillip Wood <phillip.wood@dunelm.org.uk>
> 
> Signed-off-by: Gabriel Scherer <gabriel.scherer@inria.fr>
> 
> Gabriel.Scherer (3):
>    checkout: provide hint when failing due to another worktree
>    rebase: support --ignore-other-worktrees
>    rebase: hint when failing on branch used by another worktree
> 
>   Documentation/config/advice.adoc |  3 +++
>   Documentation/git-rebase.adoc    |  6 ++++++
>   advice.c                         |  1 +
>   advice.h                         |  1 +
>   branch.c                         | 13 +++++++++++--
>   branch.h                         |  4 ++++
>   builtin/checkout.c               | 12 ++++++++++--
>   builtin/rebase.c                 | 19 ++++++++++++++++++-
>   t/t3400-rebase.sh                |  4 +++-
>   9 files changed, 57 insertions(+), 6 deletions(-)
> 

← back to recent threads