X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-checkout.sh;h=14835a4aa982af88d758ea014afacf7b2fb1bb1e;hb=4b22f634a3f1752d98e1fc5eee4fa7ce0efe157c;hp=4192a99fec1e137599b250a4f65c1b1e4201c601;hpb=67bed724f2736925f84edd0aaaf371fea83dddc2;p=git.git diff --git a/git-checkout.sh b/git-checkout.sh index 4192a99fe..14835a4aa 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -1,11 +1,13 @@ #!/bin/sh -USAGE='[-f] [-b ] [-m] [] [...]' +USAGE='[-q] [-f] [-b ] [-m] [] [...]' SUBDIRECTORY_OK=Sometimes . git-sh-setup +require_work_tree old_name=HEAD old=$(git-rev-parse --verify $old_name 2>/dev/null) +oldbranch=$(git-symbolic-ref $old_name 2>/dev/null) new= new_name= force= @@ -13,6 +15,9 @@ branch= newbranch= newbranch_log= merge= +quiet= +LF=' +' while [ "$#" != "0" ]; do arg="$1" shift @@ -36,6 +41,9 @@ while [ "$#" != "0" ]; do -m) merge=1 ;; + "-q") + quiet=1 + ;; --) break ;; @@ -50,7 +58,7 @@ while [ "$#" != "0" ]; do exit 1 fi new="$rev" - new_name="$arg^0" + new_name="$arg" if git-show-ref --verify --quiet -- "refs/heads/$arg" then branch="$arg" @@ -131,28 +139,43 @@ fi # We are switching branches and checking out trees, so # we *NEED* to be at the toplevel. -cdup=$(git-rev-parse --show-cdup) -if test ! -z "$cdup" -then - cd "$cdup" -fi +cd_to_toplevel [ -z "$new" ] && new=$old && new_name="$old_name" -# If we don't have an old branch that we're switching to, +# If we don't have an existing branch that we're switching to, # and we don't have a new branch name for the target we -# are switching to, then we'd better just be checking out -# what we already had +# are switching to, then we are detaching our HEAD from any +# branch. However, if "git checkout HEAD" detaches the HEAD +# from the current branch, even though that may be logically +# correct, it feels somewhat funny. More importantly, we do not +# want "git checkout" nor "git checkout -f" to detach HEAD. -[ -z "$branch$newbranch" ] && - [ "$new" != "$old" ] && - die "git checkout: to checkout the requested commit you need to specify - a name for a new branch which is created and switched to" +detached= +detach_warn= + +if test -z "$branch$newbranch" && test "$new" != "$old" +then + detached="$new" + if test -n "$oldbranch" && test -z "$quiet" + then + detach_warn="Note: moving to \"$new_name\" which isn't a local branch +If you want to create a new branch from this checkout, you may do so +(now or later) by using -b with the checkout command again. Example: + git checkout -b " + fi +elif test -z "$oldbranch" && test -z "$quiet" +then + echo >&2 "Previous HEAD position was $old" +fi if [ "X$old" = X ] then - echo "warning: You do not appear to currently be on a branch." >&2 - echo "warning: Forcing checkout of $new_name." >&2 + if test -z "$quiet" + then + echo >&2 "warning: You appear to be on a branch yet to be born." + echo >&2 "warning: Forcing checkout of $new_name." + fi force=1 fi @@ -171,16 +194,12 @@ else # Match the index to the working tree, and do a three-way. git diff-files --name-only | git update-index --remove --stdin && work=`git write-tree` && - git read-tree --reset -u $new && - git read-tree -m -u --aggressive --exclude-per-directory=.gitignore $old $new $work || - exit + git read-tree --reset -u $new || exit - if result=`git write-tree 2>/dev/null` - then - echo >&2 "Trivially automerged." - else - git merge-index -o git-merge-one-file -a - fi + eval GITHEAD_$new=${new_name:-${branch:-$new}} && + eval GITHEAD_$work=local && + export GITHEAD_$new GITHEAD_$work && + git merge-recursive $old -- $new $work # Do not register the cleanly merged paths in the index yet. # this is not a real merge before committing, but just carrying @@ -201,9 +220,9 @@ else exit 0 ) saved_err=$? - if test "$saved_err" = 0 + if test "$saved_err" = 0 && test -z "$quiet" then - test "$new" = "$old" || git diff-index --name-status "$new" + git diff-index --name-status "$new" fi (exit $saved_err) fi @@ -223,8 +242,30 @@ if [ "$?" -eq 0 ]; then git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit branch="$newbranch" fi - [ "$branch" ] && - GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch" + if test -n "$branch" + then + GIT_DIR="$GIT_DIR" git-symbolic-ref -m "checkout: moving to $branch" HEAD "refs/heads/$branch" + if test -z "$quiet" + then + echo >&2 "Switched to${newbranch:+ a new} branch \"$branch\"" + fi + elif test -n "$detached" + then + # NEEDSWORK: we would want a command to detach the HEAD + # atomically, instead of this handcrafted command sequence. + # Perhaps: + # git update-ref --detach HEAD $new + # or something like that... + # + git-rev-parse HEAD >"$GIT_DIR/HEAD.new" && + mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" && + git-update-ref -m "checkout: moving to $arg" HEAD "$detached" || + die "Cannot detach HEAD" + if test -n "$detach_warn" + then + echo >&2 "$detach_warn" + fi + fi rm -f "$GIT_DIR/MERGE_HEAD" else exit 1