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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: "Gabriel.Scherer" <gabriel.scherer@xxxxxxxx>

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@xxxxxxxx>
---
 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





[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux