X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-checkout.sh;h=36308d22c6a72b9ad53ced60bd3c70a2e17520b6;hb=e99fcf96deab45ca81b22948328deb2d8586aa8d;hp=2c053a33c3c78f27150cdd397ad28641787abb3a;hpb=03feddd6e8e779086ac2d131ded325f8e5601653;p=git.git diff --git a/git-checkout.sh b/git-checkout.sh index 2c053a33..36308d22 100755 --- a/git-checkout.sh +++ b/git-checkout.sh @@ -1,5 +1,7 @@ #!/bin/sh -. git-sh-setup || die "Not a git archive" + +USAGE='[-f] [-b ] [] [...]' +. git-sh-setup old=$(git-rev-parse HEAD) new= @@ -23,32 +25,83 @@ while [ "$#" != "0" ]; do "-f") force=1 ;; + --) + break + ;; + -*) + usage + ;; *) - rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) || - die "I don't know any '$arg'." - if [ -z "$rev" ]; then - echo "unknown flag $arg" - exit 1 - fi - if [ "$new" ]; then - echo "Multiple revisions?" - exit 1 - fi - new="$rev" - if [ -f "$GIT_DIR/refs/heads/$arg" ]; then - branch="$arg" + if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) + then + if [ -z "$rev" ]; then + echo "unknown flag $arg" + exit 1 + fi + new="$rev" + if [ -f "$GIT_DIR/refs/heads/$arg" ]; then + branch="$arg" + fi + elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null) + then + # checking out selected paths from a tree-ish. + new="$rev" + branch= + else + new= + branch= + set x "$arg" "$@" + shift fi + break ;; esac done -[ -z "$new" ] && new=$old +# The behaviour of the command with and without explicit path +# parameters is quite different. +# +# Without paths, we are checking out everything in the work tree, +# possibly switching branches. This is the traditional behaviour. # +# With paths, we are _never_ switching branch, but checking out +# the named paths from either index (when no rev is given), +# or the named tree-ish (when rev is given). + +if test "$#" -ge 1 +then + if test '' != "$newbranch$force" + then + die "updating paths and switching branches or forcing are incompatible." + fi + if test '' != "$new" + 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" "$@" | + git-update-index --index-info || exit $? + fi + git-checkout-index -f -u -- "$@" + exit $? +else + # Make sure we did not fall back on $arg^{tree} codepath + # since we are not checking out from an arbitrary tree-ish, + # but switching branches. + if test '' != "$new" + then + git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 || + die "Cannot switch branch to a non-commit." + fi +fi + +[ -z "$new" ] && new=$old + # 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 # are switching to, then we'd better just be checking out # what we already had -# + [ -z "$branch$newbranch" ] && [ "$new" != "$old" ] && die "git checkout: you need to specify a new branch name" @@ -63,14 +116,16 @@ else 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) # if [ "$?" -eq 0 ]; then if [ "$newbranch" ]; then - echo $new > "$GIT_DIR/refs/heads/$newbranch" + leading=`expr "refs/heads/$newbranch" : '\(.*\)/'` && + mkdir -p "$GIT_DIR/$leading" && + echo $new >"$GIT_DIR/refs/heads/$newbranch" || exit branch="$newbranch" fi [ "$branch" ] &&