* [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints
@ 2025-09-13 14:13 Gabriel Scherer
2025-09-13 14:13 ` [PATCH 1/3] checkout: provide hint when failing due to another worktree Gabriel Scherer
` (4 more replies)
0 siblings, 5 replies; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-13 14:13 UTC (permalink / raw)
To: git; +Cc: Gabriel Scherer, Junio C Hamano, D. Ben Knoble, Phillip Wood
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
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
@ 2025-09-13 14:13 ` Gabriel Scherer
2025-09-13 20:55 ` Kristoffer Haugsbakk
2025-09-13 14:13 ` [PATCH 2/3] rebase: support --ignore-other-worktrees Gabriel Scherer
` (3 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-13 14:13 UTC (permalink / raw)
To: git; +Cc: Gabriel Scherer, Junio C Hamano, D. Ben Knoble, Phillip Wood
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(-)
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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/3] rebase: support --ignore-other-worktrees
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
2025-09-13 14:13 ` [PATCH 1/3] checkout: provide hint when failing due to another worktree Gabriel Scherer
@ 2025-09-13 14:13 ` Gabriel Scherer
2025-09-15 10:09 ` Phillip Wood
2025-09-13 14:13 ` [PATCH 3/3] rebase: hint when failing on branch used by another worktree Gabriel Scherer
` (2 subsequent siblings)
4 siblings, 1 reply; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-13 14:13 UTC (permalink / raw)
To: git; +Cc: Gabriel Scherer, Junio C Hamano, D. Ben Knoble, Phillip Wood
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(-)
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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/3] rebase: hint when failing on branch used by another worktree
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
2025-09-13 14:13 ` [PATCH 1/3] checkout: provide hint when failing due to another worktree Gabriel Scherer
2025-09-13 14:13 ` [PATCH 2/3] rebase: support --ignore-other-worktrees Gabriel Scherer
@ 2025-09-13 14:13 ` Gabriel Scherer
2025-09-13 19:30 ` [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Ben Knoble
2025-09-15 10:09 ` Phillip Wood
4 siblings, 0 replies; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-13 14:13 UTC (permalink / raw)
To: git; +Cc: Gabriel Scherer, Junio C Hamano, D. Ben Knoble, Phillip Wood
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(-)
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
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
` (2 preceding siblings ...)
2025-09-13 14:13 ` [PATCH 3/3] rebase: hint when failing on branch used by another worktree Gabriel Scherer
@ 2025-09-13 19:30 ` Ben Knoble
2025-09-13 20:02 ` Gabriel Scherer
2025-09-15 10:09 ` Phillip Wood
4 siblings, 1 reply; 20+ messages in thread
From: Ben Knoble @ 2025-09-13 19:30 UTC (permalink / raw)
To: Gabriel Scherer; +Cc: git, Junio C Hamano, Phillip Wood
> 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?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints
2025-09-13 19:30 ` [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Ben Knoble
@ 2025-09-13 20:02 ` Gabriel Scherer
0 siblings, 0 replies; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-13 20:02 UTC (permalink / raw)
To: Ben Knoble; +Cc: git, Junio C Hamano, Phillip Wood
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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-13 14:13 ` [PATCH 1/3] checkout: provide hint when failing due to another worktree Gabriel Scherer
@ 2025-09-13 20:55 ` Kristoffer Haugsbakk
2025-09-14 7:50 ` Gabriel Scherer
2025-09-14 19:03 ` Ben Knoble
0 siblings, 2 replies; 20+ messages in thread
From: Kristoffer Haugsbakk @ 2025-09-13 20:55 UTC (permalink / raw)
To: Gabriel Scherer, git; +Cc: Junio C Hamano, D. Ben Knoble, Phillip Wood
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:
> 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).
>
> 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.
> 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.
> [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).
> 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”.
> + exit(code);
> + }
> + }
> free(head_ref);
> }
>
> --
> 2.51.0
No updates to tests were covered in another email.
--
Kristoffer Haugsbakk
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-13 20:55 ` Kristoffer Haugsbakk
@ 2025-09-14 7:50 ` Gabriel Scherer
2025-09-15 8:53 ` Junio C Hamano
2025-09-14 19:03 ` Ben Knoble
1 sibling, 1 reply; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-14 7:50 UTC (permalink / raw)
To: Kristoffer Haugsbakk, git; +Cc: Junio C Hamano, D. Ben Knoble, Phillip Wood
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:
>> + 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.)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-13 20:55 ` Kristoffer Haugsbakk
2025-09-14 7:50 ` Gabriel Scherer
@ 2025-09-14 19:03 ` Ben Knoble
2025-09-14 19:06 ` Ben Knoble
2025-09-14 19:32 ` Kristoffer Haugsbakk
1 sibling, 2 replies; 20+ messages in thread
From: Ben Knoble @ 2025-09-14 19:03 UTC (permalink / raw)
To: Kristoffer Haugsbakk; +Cc: Gabriel Scherer, git, Junio C Hamano, Phillip Wood
> 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?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-14 19:03 ` Ben Knoble
@ 2025-09-14 19:06 ` Ben Knoble
2025-09-14 19:32 ` Kristoffer Haugsbakk
1 sibling, 0 replies; 20+ messages in thread
From: Ben Knoble @ 2025-09-14 19:06 UTC (permalink / raw)
To: Kristoffer Haugsbakk; +Cc: Gabriel Scherer, git, Junio C Hamano, Phillip Wood
> 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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-14 19:03 ` Ben Knoble
2025-09-14 19:06 ` Ben Knoble
@ 2025-09-14 19:32 ` Kristoffer Haugsbakk
1 sibling, 0 replies; 20+ messages in thread
From: Kristoffer Haugsbakk @ 2025-09-14 19:32 UTC (permalink / raw)
To: D. Ben Knoble; +Cc: Gabriel Scherer, git, Junio C Hamano, Phillip Wood
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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-14 7:50 ` Gabriel Scherer
@ 2025-09-15 8:53 ` Junio C Hamano
2025-09-15 19:52 ` Gabriel Scherer
0 siblings, 1 reply; 20+ messages in thread
From: Junio C Hamano @ 2025-09-15 8:53 UTC (permalink / raw)
To: Gabriel Scherer; +Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
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.
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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
` (3 preceding siblings ...)
2025-09-13 19:30 ` [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Ben Knoble
@ 2025-09-15 10:09 ` Phillip Wood
4 siblings, 0 replies; 20+ messages in thread
From: Phillip Wood @ 2025-09-15 10:09 UTC (permalink / raw)
To: Gabriel Scherer, git; +Cc: Junio C Hamano, D. Ben Knoble, Phillip Wood
Hi Gabriel
On 13/09/2025 15:13, Gabriel Scherer wrote:
> 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
> 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(-)
>
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] rebase: support --ignore-other-worktrees
2025-09-13 14:13 ` [PATCH 2/3] rebase: support --ignore-other-worktrees Gabriel Scherer
@ 2025-09-15 10:09 ` Phillip Wood
2025-09-15 16:23 ` Junio C Hamano
0 siblings, 1 reply; 20+ messages in thread
From: Phillip Wood @ 2025-09-15 10:09 UTC (permalink / raw)
To: Gabriel Scherer, git; +Cc: Junio C Hamano, D. Ben Knoble, Phillip Wood
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.
Thanks
Phillip
> 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' '
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] rebase: support --ignore-other-worktrees
2025-09-15 10:09 ` Phillip Wood
@ 2025-09-15 16:23 ` Junio C Hamano
0 siblings, 0 replies; 20+ messages in thread
From: Junio C Hamano @ 2025-09-15 16:23 UTC (permalink / raw)
To: Phillip Wood; +Cc: Gabriel Scherer, git, D. Ben Knoble, Phillip Wood
Phillip Wood <phillip.wood123@gmail.com> writes:
> 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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-15 8:53 ` Junio C Hamano
@ 2025-09-15 19:52 ` Gabriel Scherer
2025-09-16 5:32 ` Junio C Hamano
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-15 19:52 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
Thanks for the detailed comments!
On 15/09/2025 10:53, Junio C Hamano wrote:
> 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.
> - '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.
> - 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.)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-15 19:52 ` Gabriel Scherer
@ 2025-09-16 5:32 ` Junio C Hamano
2025-09-17 14:17 ` Junio C Hamano
2025-09-17 15:25 ` Gabriel Scherer
2 siblings, 0 replies; 20+ messages in thread
From: Junio C Hamano @ 2025-09-16 5:32 UTC (permalink / raw)
To: Gabriel Scherer; +Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
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.
>> - '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.
> 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.
>> - 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
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-15 19:52 ` Gabriel Scherer
2025-09-16 5:32 ` Junio C Hamano
@ 2025-09-17 14:17 ` Junio C Hamano
2025-09-17 15:25 ` Gabriel Scherer
2 siblings, 0 replies; 20+ messages in thread
From: Junio C Hamano @ 2025-09-17 14:17 UTC (permalink / raw)
To: Gabriel Scherer; +Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
Gabriel Scherer <gabriel.scherer@inria.fr> writes:
> 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.
>> 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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-15 19:52 ` Gabriel Scherer
2025-09-16 5:32 ` Junio C Hamano
2025-09-17 14:17 ` Junio C Hamano
@ 2025-09-17 15:25 ` Gabriel Scherer
2025-09-19 14:13 ` Phillip Wood
2 siblings, 1 reply; 20+ messages in thread
From: Gabriel Scherer @ 2025-09-17 15:25 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
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.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/3] checkout: provide hint when failing due to another worktree
2025-09-17 15:25 ` Gabriel Scherer
@ 2025-09-19 14:13 ` Phillip Wood
0 siblings, 0 replies; 20+ messages in thread
From: Phillip Wood @ 2025-09-19 14:13 UTC (permalink / raw)
To: Gabriel Scherer, Junio C Hamano
Cc: Kristoffer Haugsbakk, git, D. Ben Knoble, Phillip Wood
Hi Gabriel
On 17/09/2025 16:25, Gabriel Scherer wrote:
> 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
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2025-09-19 14:13 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-13 14:13 [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Gabriel Scherer
2025-09-13 14:13 ` [PATCH 1/3] checkout: provide hint when failing due to another worktree Gabriel Scherer
2025-09-13 20:55 ` Kristoffer Haugsbakk
2025-09-14 7:50 ` Gabriel Scherer
2025-09-15 8:53 ` Junio C Hamano
2025-09-15 19:52 ` Gabriel Scherer
2025-09-16 5:32 ` Junio C Hamano
2025-09-17 14:17 ` Junio C Hamano
2025-09-17 15:25 ` Gabriel Scherer
2025-09-19 14:13 ` Phillip Wood
2025-09-14 19:03 ` Ben Knoble
2025-09-14 19:06 ` Ben Knoble
2025-09-14 19:32 ` Kristoffer Haugsbakk
2025-09-13 14:13 ` [PATCH 2/3] rebase: support --ignore-other-worktrees Gabriel Scherer
2025-09-15 10:09 ` Phillip Wood
2025-09-15 16:23 ` Junio C Hamano
2025-09-13 14:13 ` [PATCH 3/3] rebase: hint when failing on branch used by another worktree Gabriel Scherer
2025-09-13 19:30 ` [PATCH 0/3] extend --ignore-other-worktrees to 'rebase', add hints Ben Knoble
2025-09-13 20:02 ` Gabriel Scherer
2025-09-15 10:09 ` Phillip Wood
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).