X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-checkout.sh;h=d99688fbf2930235a01385efdd2dbc0729e660ee;hb=070879ca93a7d358086f4c8aff4553493dcb9210;hp=4c08f36b591508b5d940384db603e2f4483116d6;hpb=3eeb419968c1f8f0a762a7127db770e9d9c8037d;p=git.git diff --git a/git-checkout.sh b/git-checkout.sh index 4c08f36b..d99688fb 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -1,15 +1,15 @@ #!/bin/sh -. git-sh-setup || die "Not a git archive" -usage () { - die "usage: git checkout [-f] [-b ] [] [...]" -} +USAGE='[-f] [-b ] [-m] [] [...]' +SUBDIRECTORY_OK=Sometimes +. git-sh-setup old=$(git-rev-parse HEAD) new= force= branch= newbranch= +merge= while [ "$#" != "0" ]; do arg="$1" shift @@ -27,6 +27,9 @@ while [ "$#" != "0" ]; do "-f") force=1 ;; + -m) + merge=1 + ;; --) break ;; @@ -72,7 +75,7 @@ done if test "$#" -ge 1 then - if test '' != "$newbranch$force" + if test '' != "$newbranch$force$merge" then die "updating paths and switching branches or forcing are incompatible." fi @@ -81,8 +84,7 @@ then # from a specific tree-ish; note that this is for # rescuing paths and is never meant to remove what # is not in the named tree-ish. - git-ls-tree -r "$new" "$@" | - sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' | + git-ls-tree --full-name -r "$new" "$@" | git-update-index --index-info || exit $? fi git-checkout-index -f -u -- "$@" @@ -98,6 +100,14 @@ else fi 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 + [ -z "$new" ] && new=$old # If we don't have an old branch that we're switching to, @@ -115,11 +125,52 @@ then git-checkout-index -q -f -u -a else git-update-index --refresh >/dev/null - git-read-tree -m -u $old $new + 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 --reset $new && + git checkout-index -f -u -q -a && + git read-tree -m -u $old $new $work || 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 + + # 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=$? + git diff-files --name-status + (exit $saved_err) fi # -# Switch the HEAD pointer to the new branch if it we +# Switch the HEAD pointer to the new branch if we # checked out a branch head, and remove any potential # old MERGE_HEAD's (subsequent commits will clearly not # be based on them, since we re-set the index)