Git development
 help / color / mirror / Atom feed
* [RFC PATCH] switch: provide configurable detach
@ 2026-04-04 14:28 Thibaud CANALE
  2026-04-04 15:23 ` Pablo
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: Thibaud CANALE @ 2026-04-04 14:28 UTC (permalink / raw)
  To: git

[-- Attachment #1: Type: text/plain, Size: 5056 bytes --]

Its purpose is to provide for git-switch(1) same detach behavior on
commit it than git-checkout(1) through configuration option
`checkout.switchDetach`.

Signed-off-by: Thibaud CANALE <thican@thican.net>
---
 Documentation/config/checkout.adoc |  4 ++++
 builtin/checkout.c                 | 18 +++++++++++++++---
 t/t2060-switch.sh                  | 27 +++++++++++++++++++++++++++
 3 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/Documentation/config/checkout.adoc b/Documentation/config/checkout.adoc
index e35d2129..3a6c1049 100644
--- a/Documentation/config/checkout.adoc
+++ b/Documentation/config/checkout.adoc
@@ -22,6 +22,10 @@ commands or functionality in the future.
 	option in `git checkout` and `git switch`. See
 	linkgit:git-switch[1] and linkgit:git-checkout[1].
 
+`checkout.switchDetach`::
+	Provides for linkgit:git-switch[1] the same detach behavior on commit id
+	than linkgit:git-checkout[1] without the explicit --detach option.
+
 `checkout.workers`::
 	The number of parallel workers to use when updating the working tree.
 	The default is one, i.e. sequential execution. If set to a value less
diff --git a/builtin/checkout.c b/builtin/checkout.c
index e031e618..1da1062e 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -53,6 +53,7 @@ struct checkout_opts {
 	int force;
 	int force_detach;
 	int implicit_detach;
+	int switch_detach;  // For checkout.switchDetach configuration
 	int writeout_stage;
 	int overwrite_ignore;
 	int ignore_skipworktree;
@@ -1005,7 +1006,10 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 	else
 		strbuf_insertstr(&msg, 0, reflog_msg);
 
-	if (!strcmp(new_branch_info->name, "HEAD") && !new_branch_info->path && !opts->force_detach) {
+	if (!strcmp(new_branch_info->name, "HEAD") &&
+	    !new_branch_info->path &&
+	    !opts->force_detach &&
+	    !opts->switch_detach) {
 		/* Nothing to do. */
 	} else if (opts->force_detach || !new_branch_info->path) {	/* No longer on any branch. */
 		refs_update_ref(get_main_ref_store(the_repository), msg.buf,
@@ -1014,7 +1018,9 @@ static void update_refs_for_switch(const struct checkout_opts *opts,
 				REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
 		if (!opts->quiet) {
 			if (old_branch_info->path &&
-			    advice_enabled(ADVICE_DETACHED_HEAD) && !opts->force_detach)
+			    advice_enabled(ADVICE_DETACHED_HEAD) &&
+			    !opts->force_detach &&
+			    !opts->switch_detach)
 				detach_advice(new_branch_info->name);
 			describe_detached_head(_("HEAD is now at"), new_branch_info->commit);
 		}
@@ -1541,8 +1547,11 @@ static void die_expecting_a_branch(const struct branch_info *branch_info)
 		 */
 		code = die_message(_("a branch is expected, got '%s'"), branch_info->name);
 
-	if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD))
+	if (advice_enabled(ADVICE_SUGGEST_DETACHING_HEAD)) {
 		advise(_("If you want to detach HEAD at the commit, try again with the --detach option."));
+		advise(_("Also you can detach by default by setting the config variable "
+		         "checkout.switchDetach to true."));
+	}
 
 	exit(code);
 }
@@ -1660,6 +1669,7 @@ static int checkout_branch(struct checkout_opts *opts,
 
 	if (!opts->implicit_detach &&
 	    !opts->force_detach &&
+	    !opts->switch_detach &&
 	    !opts->new_branch &&
 	    !opts->new_branch_force &&
 	    new_branch_info->name &&
@@ -2119,6 +2129,8 @@ int cmd_switch(int argc,
 	options = add_common_options(&opts, options);
 	options = add_common_switch_branch_options(&opts, options);
 
+	repo_config_get_bool(the_repository, "checkout.switchDetach", &opts.switch_detach);
+
 	cb_option = 'c';
 
 	return checkout_main(argc, argv, prefix, &opts, options,
diff --git a/t/t2060-switch.sh b/t/t2060-switch.sh
index c91c4db9..3435ae98 100755
--- a/t/t2060-switch.sh
+++ b/t/t2060-switch.sh
@@ -177,4 +177,31 @@ test_expect_success 'switch back when temporarily detached and checked out elsew
 	git -C wt2 switch --ignore-other-worktrees shared
 '
 
+test_expect_success 'switch with configured detach behavior from configuration ' '
+	test_when_finished "
+		test_config checkout.switchDetach false;
+		git switch main
+	" &&
+	test_config checkout.switchDetach true &&
+	git switch main &&
+	git symbolic-ref HEAD &&
+	git switch main~ &&
+	test_must_fail git symbolic-ref HEAD &&
+	git switch - &&
+	git symbolic-ref HEAD &&
+	git switch - &&
+	test_must_fail git symbolic-ref HEAD
+'
+
+test_expect_success 'switch without configured detach behavior from configuration ' '
+	test_when_finished "
+		test_config checkout.switchDetach false;
+		git switch main
+	" &&
+	test_config checkout.switchDetach false &&
+	git switch main &&
+	git symbolic-ref HEAD &&
+	test_must_fail git switch main~
+'
+
 test_done

base-commit: 2855562ca6a9c6b0e7bc780b050c1e83c9fcfbd0
-- 
Thibaud CANALE
thican [at] thican [dot] net
https://thican.net/
GPG: rsa4096 2013-10-14 485EF628CB85CDD4CB7CFF0D52F5127650733A18

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 870 bytes --]

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-04-07  0:50 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-04 14:28 [RFC PATCH] switch: provide configurable detach Thibaud CANALE
2026-04-04 15:23 ` Pablo
2026-04-04 21:10   ` Thibaud CANALE
2026-04-04 16:58 ` D. Ben Knoble
2026-04-04 21:26   ` Thibaud CANALE
2026-04-04 21:14 ` [RFC PATCH v2] " Thibaud CANALE
2026-04-06 16:36 ` [RFC PATCH] " Junio C Hamano
2026-04-06 17:48   ` Kristoffer Haugsbakk
2026-04-07  0:50     ` Junio C Hamano

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox