1#!/bin/sh
2. git-sh-setup || die "Not a git archive"
34
old=$(git-rev-parse HEAD)
5new=
6force=
7branch=
8newbranch=
9while [ "$#" != "0" ]; do
10arg="$1"
11shift
12case "$arg" in
13"-b")
14newbranch="$1"
15shift
16[ -z "$newbranch" ] &&
17die "git checkout: -b needs a branch name"
18[ -e "$GIT_DIR/refs/heads/$newbranch" ] &&
19die "git checkout: branch $newbranch already exists"
20git-check-ref-format "heads/$newbranch" ||
21die "we do not like '$newbranch' as a branch name."
22;;
23"-f")
24force=1
25;;
26--)
27break
28;;
29*)
30if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null)
31then
32if [ -z "$rev" ]; then
33echo "unknown flag $arg"
34exit 1
35fi
36new="$rev"
37if [ -f "$GIT_DIR/refs/heads/$arg" ]; then
38branch="$arg"
39fi
40elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null)
41then
42# checking out selected paths from a tree-ish.
43new="$rev"
44branch=
45else
46new=
47branch=
48set x "$arg" "$@"
49shift
50fi
51break
52;;
53esac
54done
5556
# The behaviour of the command with and without explicit path
57# parameters is quite different.
58#
59# Without paths, we are checking out everything in the work tree,
60# possibly switching branches. This is the traditional behaviour.
61#
62# With paths, we are _never_ switching branch, but checking out
63# the named paths from either index (when no rev is given),
64# or the named tree-ish (when rev is given).
6566
if test "$#" -ge 1
67then
68if test '' != "$newbranch$force"
69then
70die "updating paths and switching branches or forcing are incompatible."
71fi
72if test '' != "$new"
73then
74# from a specific tree-ish; note that this is for
75# rescuing paths and is never meant to remove what
76# is not in the named tree-ish.
77git-ls-tree -r "$new" "$@" |
78sed -ne 's/^\([0-7]*\) blob \(.*\)$/\1 \2/p' |
79git-update-index --index-info || exit $?
80fi
81git-checkout-index -f -u -- "$@"
82exit $?
83else
84# Make sure we did not fall back on $arg^{tree} codepath
85# since we are not checking out from an arbitrary tree-ish,
86# but switching branches.
87if test '' != "$new"
88then
89git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 ||
90die "Cannot switch branch to a non-commit."
91fi
92fi
9394
[ -z "$new" ] && new=$old
9596
# If we don't have an old branch that we're switching to,
97# and we don't have a new branch name for the target we
98# are switching to, then we'd better just be checking out
99# what we already had
100101
[ -z "$branch$newbranch" ] &&
102[ "$new" != "$old" ] &&
103die "git checkout: you need to specify a new branch name"
104105
if [ "$force" ]
106then
107git-read-tree --reset $new &&
108git-checkout-index -q -f -u -a
109else
110git-update-index --refresh >/dev/null
111git-read-tree -m -u $old $new
112fi
113114
#
115# Switch the HEAD pointer to the new branch if it we
116# checked out a branch head, and remove any potential
117# old MERGE_HEAD's (subsequent commits will clearly not
118# be based on them, since we re-set the index)
119#
120if [ "$?" -eq 0 ]; then
121if [ "$newbranch" ]; then
122echo $new > "$GIT_DIR/refs/heads/$newbranch"
123branch="$newbranch"
124fi
125[ "$branch" ] &&
126GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch"
127rm -f "$GIT_DIR/MERGE_HEAD"
128else
129exit 1
130fi