X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-checkout.sh;h=e02d4d87f622bf73ad04c356ff15ac6e0a626aa6;hb=8860fd42fcf5a7853f7d7c2198793183320293ff;hp=119bca1ffbfb8fb0dae404a8e7389f577aebc42c;hpb=6a96b32d3b045c6e8d1b553fd6b64e03db9b0e45;p=git.git diff --git a/git-checkout.sh b/git-checkout.sh index 119bca1ff..e02d4d87f 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -3,9 +3,11 @@ USAGE='[-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,8 @@ branch= newbranch= newbranch_log= merge= +LF=' +' while [ "$#" != "0" ]; do arg="$1" shift @@ -50,7 +54,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" @@ -77,6 +81,11 @@ while [ "$#" != "0" ]; do esac done +case "$force$merge" in +11) + die "git checkout: -f and -m are incompatible" +esac + # The behaviour of the command with and without explicit path # parameters is quite different. # @@ -107,7 +116,11 @@ Did you intend to checkout '$@' which can not be resolved as commit?" git-ls-tree --full-name -r "$new" "$@" | git-update-index --index-info || exit $? fi - git-checkout-index -f -u -- "$@" + + # Make sure the request is about existing paths. + git-ls-files --error-unmatch -- "$@" >/dev/null || exit + git-ls-files -- "$@" | + git-checkout-index -f -u --stdin exit $? else # Make sure we did not fall back on $arg^{tree} codepath @@ -122,28 +135,53 @@ 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" + then + detach_warn="warning: you are not on ANY branch anymore. +If you meant to create a new branch from the commit, you need -b to +associate a new branch with the wanted checkout. Example: + git checkout -b $arg" + fi +elif test -z "$oldbranch" && test -n "$branch" +then + # Coming back... + if test -z "$force" + then + git show-ref -d -s | grep "$old" >/dev/null || { + echo >&2 \ +"You are not on any branch and switching to branch '$new_name' +may lose your changes. At this point, you can do one of two things: + (1) Decide it is Ok and say 'git checkout -f $new_name'; + (2) Start a new branch from the current commit, by saying + 'git checkout -b '. +Leaving your HEAD detached; not switching to branch '$new_name'." + exit 1; + } + fi +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 + echo >&2 "warning: You appear to be on a branch yet to be born." + echo >&2 "warning: Forcing checkout of $new_name." force=1 fi @@ -152,7 +190,7 @@ then git-read-tree --reset -u $new else git-update-index --refresh >/dev/null - merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( + merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || ( case "$merge" in '') echo >&2 "$merge_error" @@ -163,7 +201,9 @@ else 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 $old $new $work || exit + eval GITHEAD_$new=${new_name:-${branch:-$new}} GITHEAD_$work=local && + export GITHEAD_$new GITHEAD_$work && + git merge-recursive $old -- $new $work || exit if result=`git write-tree 2>/dev/null` then @@ -213,8 +253,25 @@ 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 HEAD "refs/heads/$branch" + 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... + # + echo "$detached" >"$GIT_DIR/HEAD.new" && + mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" || + 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