X-Git-Url: https://git.octo.it/?p=git.git;a=blobdiff_plain;f=git-checkout.sh;h=564117f0064aba32e190a49106eaecfdb422b31e;hp=76e6a41c6cd9a0e5c87b64132f6af02570f00983;hb=HEAD;hpb=19205acfc29b6d39b5643a7f9a2448f89df14355 diff --git a/git-checkout.sh b/git-checkout.sh index 76e6a41c..564117f0 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -1,14 +1,18 @@ #!/bin/sh -USAGE='[-f] [-b ] [] [...]' +USAGE='[-f] [-b ] [-m] [] [...]' SUBDIRECTORY_OK=Sometimes . git-sh-setup old=$(git-rev-parse HEAD) +old_name=HEAD new= +new_name= force= branch= newbranch= +newbranch_log= +merge= while [ "$#" != "0" ]; do arg="$1" shift @@ -21,11 +25,17 @@ while [ "$#" != "0" ]; do [ -e "$GIT_DIR/refs/heads/$newbranch" ] && die "git checkout: branch $newbranch already exists" git-check-ref-format "heads/$newbranch" || - die "we do not like '$newbranch' as a branch name." + die "git checkout: we do not like '$newbranch' as a branch name." + ;; + "-l") + newbranch_log=1 ;; "-f") force=1 ;; + -m) + merge=1 + ;; --) break ;; @@ -40,6 +50,7 @@ while [ "$#" != "0" ]; do exit 1 fi new="$rev" + new_name="$arg^0" if [ -f "$GIT_DIR/refs/heads/$arg" ]; then branch="$arg" fi @@ -47,9 +58,11 @@ while [ "$#" != "0" ]; do then # checking out selected paths from a tree-ish. new="$rev" + new_name="$arg^{tree}" branch= else new= + new_name= branch= set x "$arg" "$@" shift @@ -71,9 +84,15 @@ done if test "$#" -ge 1 then - if test '' != "$newbranch$force" + hint= + if test "$#" -eq 1 + then + hint=" +Did you intend to checkout '$@' which can not be resolved as commit?" + fi + if test '' != "$newbranch$force$merge" then - die "updating paths and switching branches or forcing are incompatible." + die "git checkout: updating paths is incompatible with switching branches/forcing$hint" fi if test '' != "$new" then @@ -104,7 +123,7 @@ then cd "$cdup" fi -[ -z "$new" ] && new=$old +[ -z "$new" ] && new=$old && new_name="$old_name" # If we don't have an old branch that we're switching to, # and we don't have a new branch name for the target we @@ -113,7 +132,8 @@ fi [ -z "$branch$newbranch" ] && [ "$new" != "$old" ] && - die "git checkout: you need to specify a new branch name" + die "git checkout: to checkout the requested commit you need to specify + a name for a new branch which is created and switched to" if [ "$force" ] then @@ -121,33 +141,51 @@ then git-checkout-index -q -f -u -a else git-update-index --refresh >/dev/null - git-read-tree -m -u $old $new || ( - echo >&2 -n "Try automerge [y/N]? " - read yesno - case "$yesno" in [yY]*) ;; *) exit 1 ;; esac - - # NEEDSWORK: We may want to reset the index from the $new for - # these paths after the automerge happens, but it is not done - # yet. Probably we need to leave unmerged ones alone, and - # yank the object name & mode from $new for cleanly merged - # paths and stuff them in the index. - - names=`git diff-files --name-only` - case "$names" in - '') ;; - *) - echo "$names" | git update-index --remove --stdin ;; + merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( + case "$merge" in + '') + echo >&2 "$merge_error" + exit 1 ;; esac + # 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 -m -u $old $work $new || exit + git read-tree --reset $new && + git checkout-index -f -u -q -a && + git read-tree -m -u --aggressive $old $new $work || exit + if result=`git write-tree 2>/dev/null` then - echo >&2 "Trivially automerged." ;# can this even happen? - exit 0 + echo >&2 "Trivially automerged." + else + git merge-index -o git-merge-one-file -a fi - git merge-index -o git-merge-one-file -a + + # Do not register the cleanly merged paths in the index yet. + # this is not a real merge before committing, but just carrying + # the working tree changes along. + unmerged=`git ls-files -u` + git read-tree --reset $new + case "$unmerged" in + '') ;; + *) + ( + z40=0000000000000000000000000000000000000000 + echo "$unmerged" | + sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" + echo "$unmerged" + ) | git update-index --index-info + ;; + esac + exit 0 ) + saved_err=$? + if test "$saved_err" = 0 + then + test "$new" = "$old" || git diff-index --name-status "$new" + fi + (exit $saved_err) fi # @@ -158,9 +196,11 @@ fi # if [ "$?" -eq 0 ]; then if [ "$newbranch" ]; then - leading=`expr "refs/heads/$newbranch" : '\(.*\)/'` && - mkdir -p "$GIT_DIR/$leading" && - echo $new >"$GIT_DIR/refs/heads/$newbranch" || exit + if [ "$newbranch_log" ]; then + mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch") + touch "$GIT_DIR/logs/refs/heads/$newbranch" + fi + git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit branch="$newbranch" fi [ "$branch" ] &&