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 <junkio@xxxxxxx> --- 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 - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html