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

From: Phillip Wood <[email-masked]>
Date: Mon, 15 Sep 2025 11:09:48 +0100

Hi Gabriel

On 13/09/2025 15:13, Gabriel Scherer wrote:
> From: "Gabriel.Scherer" <[email-masked]>
> 
> 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 <[email-masked]>
> ---
>   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' '