Thread (2 messages) 2 messages, 2 authors, 2016-06-15
DORMANTno replies

[PATCH] checkout -d: explicitly detach HEAD even when switching to the tip of a branch

From: Junio C Hamano <hidden>
Date: 2016-06-15 22:43:02
Subsystem: documentation, the rest · Maintainers: Jonathan Corbet, Linus Torvalds

You cannot currently checkout the tip of an existing branch
without moving to the branch.

This allows you to detach your HEAD and place it at such a
commit, with:

    $ git checkout -d master

Signed-off-by: Junio C Hamano <redacted>
---
 Documentation/git-checkout.txt |    6 +++-
 git-checkout.sh                |   18 +++++++++--
 t/t7201-co.sh                  |   63 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 81 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index f5b2d50..d00eeaa 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -8,7 +8,7 @@ git-checkout - Checkout and switch to a branch
 SYNOPSIS
 --------
 [verse]
-'git-checkout' [-q] [-f] [-b [--track | --no-track] <new_branch> [-l]] [-m] [<branch>]
+'git-checkout' [-q] [-f] [-b [--track | --no-track] <new_branch> [-l] | -d] [-m] [<branch>]
 'git-checkout' [<tree-ish>] <paths>...
 
 DESCRIPTION
@@ -61,6 +61,10 @@ OPTIONS
 	all changes to made the branch ref, enabling use of date
 	based sha1 expressions such as "<branchname>@{yesterday}".
 
+-d::
+	Explicitly ask to detach HEAD, even when named revision
+	to switch to is at the tip of a branch.
+
 -m::
 	If you have local modifications to one or more files that
 	are different between the current branch and the branch to
diff --git a/git-checkout.sh b/git-checkout.sh
index a7390e8..e551443 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-USAGE='[-q] [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
+USAGE='[-q] [-f] [-b <new_branch> | -d] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 require_work_tree
@@ -17,6 +17,7 @@ newbranch=
 newbranch_log=
 merge=
 quiet=
+explicit_detach=
 LF='
 '
 while [ "$#" != "0" ]; do
@@ -39,6 +40,9 @@ while [ "$#" != "0" ]; do
 	"--track"|"--no-track")
 		track="$arg"
 		;;
+	-d)
+		explicit_detach=1
+		;;
 	"-f")
 		force=1
 		;;
@@ -94,6 +98,11 @@ case "$newbranch,$track" in
 	die "git checkout: --track and --no-track require -b"
 esac
 
+case "$newbranch$explicit_detach" in
+11)
+	die "git checkout: -d and -b are incompatible"
+esac
+
 case "$force$merge" in
 11)
 	die "git checkout: -f and -m are incompatible"
@@ -117,7 +126,7 @@ then
 		hint="
 Did you intend to checkout '$@' which can not be resolved as commit?"
 	fi
-	if test '' != "$newbranch$force$merge"
+	if test '' != "$newbranch$force$merge$explicit_detach"
 	then
 		die "git checkout: updating paths is incompatible with switching branches/forcing$hint"
 	fi
@@ -170,7 +179,8 @@ describe_detached_head () {
 	}
 }
 
-if test -z "$branch$newbranch" && test "$new" != "$old"
+if test -z "$branch$newbranch" && test "$new" != "$old" ||
+   test -n "$explicit_detach"
 then
 	detached="$new"
 	if test -n "$oldbranch" && test -z "$quiet"
@@ -254,7 +264,7 @@ if [ "$?" -eq 0 ]; then
 		git-branch $track $newbranch_log "$newbranch" "$new_name" || exit
 		branch="$newbranch"
 	fi
-	if test -n "$branch"
+	if test -n "$branch" && test -z "$explicit_detach"
 	then
 		GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch"
 		if test -n "$quiet"
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 867bbd2..caa04f9 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -3,7 +3,20 @@
 # Copyright (c) 2006 Junio C Hamano
 #
 
-test_description='git-checkout tests.'
+test_description='git-checkout tests.
+
+Creates master, forks renamer and side branches from it.
+Test switching across them.
+
+  ! [master] Initial A one, A two
+   * [renamer] Renamer R one->uno, M two
+    ! [side] Side M one, D two, A three
+  ---
+    + [side] Side M one, D two, A three
+   *  [renamer] Renamer R one->uno, M two
+  +*+ [master] Initial A one, A two
+
+'
 
 . ./test-lib.sh
 
@@ -129,4 +142,52 @@ test_expect_success 'checkout -m with merge conflict' '
 	! test -s current
 '
 
+test_expect_success 'checkout to detach HEAD' '
+
+	git checkout -f renamer && git clean &&
+	git checkout renamer^ &&
+	H=$(git rev-parse --verify HEAD) &&
+	M=$(git show-ref -s --verify refs/heads/master) &&
+	test "z$H" = "z$M" &&
+	if git symbolic-ref HEAD >/dev/null 2>&1
+	then
+		echo "OOPS, HEAD is still symbolic???"
+		false
+	else
+		: happy
+	fi
+'
+
+test_expect_success 'checkout to detach HEAD with explicit -d' '
+
+	git checkout -f master && git clean &&
+	git checkout -d renamer^ &&
+	H=$(git rev-parse --verify HEAD) &&
+	M=$(git show-ref -s --verify refs/heads/master) &&
+	test "z$H" = "z$M" &&
+	if git symbolic-ref HEAD >/dev/null 2>&1
+	then
+		echo "OOPS, HEAD is still symbolic???"
+		false
+	else
+		: happy
+	fi
+'
+
+test_expect_success 'checkout to detach HEAD with explicit -d' '
+
+	git checkout -f master && git clean &&
+	git checkout -d &&
+	H=$(git rev-parse --verify HEAD) &&
+	M=$(git show-ref -s --verify refs/heads/master) &&
+	test "z$H" = "z$M" &&
+	if git symbolic-ref HEAD >/dev/null 2>&1
+	then
+		echo "OOPS, HEAD is still symbolic???"
+		false
+	else
+		: happy
+	fi
+'
+
 test_done
-- 
1.5.1.rc3.1.ga429d
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help