git-checkout.shon commit Print out the edge commits for each packfile in fast-import. (2369ed7)
   1#!/bin/sh
   2
   3USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
   4SUBDIRECTORY_OK=Sometimes
   5. git-sh-setup
   6require_work_tree
   7
   8old_name=HEAD
   9old=$(git-rev-parse --verify $old_name 2>/dev/null)
  10oldbranch=$(git-symbolic-ref $old_name 2>/dev/null)
  11new=
  12new_name=
  13force=
  14branch=
  15newbranch=
  16newbranch_log=
  17merge=
  18LF='
  19'
  20while [ "$#" != "0" ]; do
  21    arg="$1"
  22    shift
  23    case "$arg" in
  24        "-b")
  25                newbranch="$1"
  26                shift
  27                [ -z "$newbranch" ] &&
  28                        die "git checkout: -b needs a branch name"
  29                git-show-ref --verify --quiet -- "refs/heads/$newbranch" &&
  30                        die "git checkout: branch $newbranch already exists"
  31                git-check-ref-format "heads/$newbranch" ||
  32                        die "git checkout: we do not like '$newbranch' as a branch name."
  33                ;;
  34        "-l")
  35                newbranch_log=1
  36                ;;
  37        "-f")
  38                force=1
  39                ;;
  40        -m)
  41                merge=1
  42                ;;
  43        --)
  44                break
  45                ;;
  46        -*)
  47                usage
  48                ;;
  49        *)
  50                if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null)
  51                then
  52                        if [ -z "$rev" ]; then
  53                                echo "unknown flag $arg"
  54                                exit 1
  55                        fi
  56                        new="$rev"
  57                        new_name="$arg"
  58                        if git-show-ref --verify --quiet -- "refs/heads/$arg"
  59                        then
  60                                branch="$arg"
  61                        fi
  62                elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
  63                then
  64                        # checking out selected paths from a tree-ish.
  65                        new="$rev"
  66                        new_name="$arg^{tree}"
  67                        branch=
  68                else
  69                        new=
  70                        new_name=
  71                        branch=
  72                        set x "$arg" "$@"
  73                        shift
  74                fi
  75                case "$1" in
  76                --)
  77                        shift ;;
  78                esac
  79                break
  80                ;;
  81    esac
  82done
  83
  84case "$force$merge" in
  8511)
  86        die "git checkout: -f and -m are incompatible"
  87esac
  88
  89# The behaviour of the command with and without explicit path
  90# parameters is quite different.
  91#
  92# Without paths, we are checking out everything in the work tree,
  93# possibly switching branches.  This is the traditional behaviour.
  94#
  95# With paths, we are _never_ switching branch, but checking out
  96# the named paths from either index (when no rev is given),
  97# or the named tree-ish (when rev is given).
  98
  99if test "$#" -ge 1
 100then
 101        hint=
 102        if test "$#" -eq 1
 103        then
 104                hint="
 105Did you intend to checkout '$@' which can not be resolved as commit?"
 106        fi
 107        if test '' != "$newbranch$force$merge"
 108        then
 109                die "git checkout: updating paths is incompatible with switching branches/forcing$hint"
 110        fi
 111        if test '' != "$new"
 112        then
 113                # from a specific tree-ish; note that this is for
 114                # rescuing paths and is never meant to remove what
 115                # is not in the named tree-ish.
 116                git-ls-tree --full-name -r "$new" "$@" |
 117                git-update-index --index-info || exit $?
 118        fi
 119
 120        # Make sure the request is about existing paths.
 121        git-ls-files --error-unmatch -- "$@" >/dev/null || exit
 122        git-ls-files -- "$@" |
 123        git-checkout-index -f -u --stdin
 124        exit $?
 125else
 126        # Make sure we did not fall back on $arg^{tree} codepath
 127        # since we are not checking out from an arbitrary tree-ish,
 128        # but switching branches.
 129        if test '' != "$new"
 130        then
 131                git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
 132                die "Cannot switch branch to a non-commit."
 133        fi
 134fi
 135
 136# We are switching branches and checking out trees, so
 137# we *NEED* to be at the toplevel.
 138cdup=$(git-rev-parse --show-cdup)
 139if test ! -z "$cdup"
 140then
 141        cd "$cdup"
 142fi
 143
 144[ -z "$new" ] && new=$old && new_name="$old_name"
 145
 146# If we don't have an existing branch that we're switching to,
 147# and we don't have a new branch name for the target we
 148# are switching to, then we are detaching our HEAD from any
 149# branch.  However, if "git checkout HEAD" detaches the HEAD
 150# from the current branch, even though that may be logically
 151# correct, it feels somewhat funny.  More importantly, we do not
 152# want "git checkout" nor "git checkout -f" to detach HEAD.
 153
 154detached=
 155detach_warn=
 156
 157if test -z "$branch$newbranch" && test "$new" != "$old"
 158then
 159        detached="$new"
 160        if test -n "$oldbranch"
 161        then
 162                detach_warn="warning: you are not on ANY branch anymore.
 163If you meant to create a new branch from the commit, you need -b to
 164associate a new branch with the wanted checkout.  Example:
 165  git checkout -b <new_branch_name> $arg"
 166        fi
 167elif test -z "$oldbranch" && test -n "$branch"
 168then
 169        # Coming back...
 170        if test -z "$force"
 171        then
 172                git show-ref -d -s | grep "$old" >/dev/null || {
 173                        echo >&2 \
 174"You are not on any branch and switching to branch '$new_name'
 175may lose your changes.  At this point, you can do one of two things:
 176 (1) Decide it is Ok and say 'git checkout -f $new_name';
 177 (2) Start a new branch from the current commit, by saying
 178     'git checkout -b <branch-name>'.
 179Leaving your HEAD detached; not switching to branch '$new_name'."
 180                        exit 1;
 181                }
 182        fi
 183fi
 184
 185if [ "X$old" = X ]
 186then
 187        echo >&2 "warning: You appear to be on a branch yet to be born."
 188        echo >&2 "warning: Forcing checkout of $new_name."
 189        force=1
 190fi
 191
 192if [ "$force" ]
 193then
 194    git-read-tree --reset -u $new
 195else
 196    git-update-index --refresh >/dev/null
 197    merge_error=$(git-read-tree -m -u --exclude-per-directory=.gitignore $old $new 2>&1) || (
 198        case "$merge" in
 199        '')
 200                echo >&2 "$merge_error"
 201                exit 1 ;;
 202        esac
 203
 204        # Match the index to the working tree, and do a three-way.
 205        git diff-files --name-only | git update-index --remove --stdin &&
 206        work=`git write-tree` &&
 207        git read-tree --reset -u $new &&
 208        git read-tree -m -u --aggressive --exclude-per-directory=.gitignore $old $new $work ||
 209        exit
 210
 211        if result=`git write-tree 2>/dev/null`
 212        then
 213            echo >&2 "Trivially automerged."
 214        else
 215            git merge-index -o git-merge-one-file -a
 216        fi
 217
 218        # Do not register the cleanly merged paths in the index yet.
 219        # this is not a real merge before committing, but just carrying
 220        # the working tree changes along.
 221        unmerged=`git ls-files -u`
 222        git read-tree --reset $new
 223        case "$unmerged" in
 224        '')     ;;
 225        *)
 226                (
 227                        z40=0000000000000000000000000000000000000000
 228                        echo "$unmerged" |
 229                        sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
 230                        echo "$unmerged"
 231                ) | git update-index --index-info
 232                ;;
 233        esac
 234        exit 0
 235    )
 236    saved_err=$?
 237    if test "$saved_err" = 0
 238    then
 239        test "$new" = "$old" || git diff-index --name-status "$new"
 240    fi
 241    (exit $saved_err)
 242fi
 243
 244# 
 245# Switch the HEAD pointer to the new branch if we
 246# checked out a branch head, and remove any potential
 247# old MERGE_HEAD's (subsequent commits will clearly not
 248# be based on them, since we re-set the index)
 249#
 250if [ "$?" -eq 0 ]; then
 251        if [ "$newbranch" ]; then
 252                if [ "$newbranch_log" ]; then
 253                        mkdir -p $(dirname "$GIT_DIR/logs/refs/heads/$newbranch")
 254                        touch "$GIT_DIR/logs/refs/heads/$newbranch"
 255                fi
 256                git-update-ref -m "checkout: Created from $new_name" "refs/heads/$newbranch" $new || exit
 257                branch="$newbranch"
 258        fi
 259        if test -n "$branch"
 260        then
 261                GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
 262        elif test -n "$detached"
 263        then
 264                # NEEDSWORK: we would want a command to detach the HEAD
 265                # atomically, instead of this handcrafted command sequence.
 266                # Perhaps:
 267                #       git update-ref --detach HEAD $new
 268                # or something like that...
 269                #
 270                echo "$detached" >"$GIT_DIR/HEAD.new" &&
 271                mv "$GIT_DIR/HEAD.new" "$GIT_DIR/HEAD" ||
 272                        die "Cannot detach HEAD"
 273                if test -n "$detach_warn"
 274                then
 275                        echo >&2 "$detach_warn"
 276                fi
 277        fi
 278        rm -f "$GIT_DIR/MERGE_HEAD"
 279else
 280        exit 1
 281fi