]>
Commit | Line | Data |
---|---|---|
303e5f4c | 1 | #!/bin/sh |
b33e9666 | 2 | |
1be0659e | 3 | USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]' |
104f3e03 | 4 | SUBDIRECTORY_OK=Sometimes |
806f36d4 | 5 | . git-sh-setup |
b0bafe03 | 6 | |
303e5f4c | 7 | old=$(git-rev-parse HEAD) |
e8b11749 | 8 | new= |
a79944d7 | 9 | force= |
e8b11749 | 10 | branch= |
91dcdfd3 | 11 | newbranch= |
1be0659e | 12 | merge= |
e8b11749 LT |
13 | while [ "$#" != "0" ]; do |
14 | arg="$1" | |
15 | shift | |
16 | case "$arg" in | |
91dcdfd3 LT |
17 | "-b") |
18 | newbranch="$1" | |
19 | shift | |
20 | [ -z "$newbranch" ] && | |
21 | die "git checkout: -b needs a branch name" | |
22 | [ -e "$GIT_DIR/refs/heads/$newbranch" ] && | |
23 | die "git checkout: branch $newbranch already exists" | |
03feddd6 | 24 | git-check-ref-format "heads/$newbranch" || |
babfaf8d | 25 | die "git checkout: we do not like '$newbranch' as a branch name." |
91dcdfd3 | 26 | ;; |
303e5f4c | 27 | "-f") |
e8b11749 | 28 | force=1 |
303e5f4c | 29 | ;; |
1be0659e JH |
30 | -m) |
31 | merge=1 | |
32 | ;; | |
4aaa7027 JH |
33 | --) |
34 | break | |
35 | ;; | |
b0bafe03 CS |
36 | -*) |
37 | usage | |
38 | ;; | |
303e5f4c | 39 | *) |
4aaa7027 JH |
40 | if rev=$(git-rev-parse --verify "$arg^0" 2>/dev/null) |
41 | then | |
42 | if [ -z "$rev" ]; then | |
43 | echo "unknown flag $arg" | |
44 | exit 1 | |
45 | fi | |
46 | new="$rev" | |
47 | if [ -f "$GIT_DIR/refs/heads/$arg" ]; then | |
48 | branch="$arg" | |
49 | fi | |
50 | elif rev=$(git-rev-parse --verify "$arg^{tree}" 2>/dev/null) | |
51 | then | |
52 | # checking out selected paths from a tree-ish. | |
53 | new="$rev" | |
54 | branch= | |
55 | else | |
56 | new= | |
57 | branch= | |
58 | set x "$arg" "$@" | |
59 | shift | |
e8b11749 | 60 | fi |
4aaa7027 | 61 | break |
e8b11749 | 62 | ;; |
303e5f4c | 63 | esac |
303e5f4c LT |
64 | done |
65 | ||
4aaa7027 JH |
66 | # The behaviour of the command with and without explicit path |
67 | # parameters is quite different. | |
68 | # | |
69 | # Without paths, we are checking out everything in the work tree, | |
70 | # possibly switching branches. This is the traditional behaviour. | |
91dcdfd3 | 71 | # |
4aaa7027 JH |
72 | # With paths, we are _never_ switching branch, but checking out |
73 | # the named paths from either index (when no rev is given), | |
74 | # or the named tree-ish (when rev is given). | |
75 | ||
76 | if test "$#" -ge 1 | |
77 | then | |
babfaf8d JW |
78 | hint= |
79 | if test "$#" -eq 1 | |
80 | then | |
81 | hint=" | |
82 | Did you intend to checkout '$@' which can not be resolved as commit?" | |
83 | fi | |
1be0659e | 84 | if test '' != "$newbranch$force$merge" |
4aaa7027 | 85 | then |
babfaf8d | 86 | die "git checkout: updating paths is incompatible with switching branches/forcing$hint" |
4aaa7027 JH |
87 | fi |
88 | if test '' != "$new" | |
89 | then | |
90 | # from a specific tree-ish; note that this is for | |
91 | # rescuing paths and is never meant to remove what | |
92 | # is not in the named tree-ish. | |
d0d14cf3 | 93 | git-ls-tree --full-name -r "$new" "$@" | |
4aaa7027 JH |
94 | git-update-index --index-info || exit $? |
95 | fi | |
96 | git-checkout-index -f -u -- "$@" | |
97 | exit $? | |
98 | else | |
99 | # Make sure we did not fall back on $arg^{tree} codepath | |
100 | # since we are not checking out from an arbitrary tree-ish, | |
101 | # but switching branches. | |
102 | if test '' != "$new" | |
103 | then | |
104 | git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 || | |
105 | die "Cannot switch branch to a non-commit." | |
106 | fi | |
107 | fi | |
108 | ||
104f3e03 JH |
109 | # We are switching branches and checking out trees, so |
110 | # we *NEED* to be at the toplevel. | |
111 | cdup=$(git-rev-parse --show-cdup) | |
112 | if test ! -z "$cdup" | |
113 | then | |
114 | cd "$cdup" | |
115 | fi | |
116 | ||
4aaa7027 JH |
117 | [ -z "$new" ] && new=$old |
118 | ||
91dcdfd3 LT |
119 | # If we don't have an old branch that we're switching to, |
120 | # and we don't have a new branch name for the target we | |
121 | # are switching to, then we'd better just be checking out | |
122 | # what we already had | |
4aaa7027 | 123 | |
91dcdfd3 LT |
124 | [ -z "$branch$newbranch" ] && |
125 | [ "$new" != "$old" ] && | |
babfaf8d JW |
126 | die "git checkout: to checkout the requested commit you need to specify |
127 | a name for a new branch which is created and switched to" | |
91dcdfd3 | 128 | |
a79944d7 | 129 | if [ "$force" ] |
303e5f4c LT |
130 | then |
131 | git-read-tree --reset $new && | |
215a7ad1 | 132 | git-checkout-index -q -f -u -a |
303e5f4c | 133 | else |
7f88c846 | 134 | git-update-index --refresh >/dev/null |
1be0659e JH |
135 | merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( |
136 | case "$merge" in | |
137 | '') | |
138 | echo >&2 "$merge_error" | |
139 | exit 1 ;; | |
19205acf JH |
140 | esac |
141 | ||
1be0659e JH |
142 | # Match the index to the working tree, and do a three-way. |
143 | git diff-files --name-only | git update-index --remove --stdin && | |
19205acf | 144 | work=`git write-tree` && |
1be0659e JH |
145 | git read-tree --reset $new && |
146 | git checkout-index -f -u -q -a && | |
147 | git read-tree -m -u $old $new $work || exit | |
148 | ||
19205acf JH |
149 | if result=`git write-tree 2>/dev/null` |
150 | then | |
1be0659e JH |
151 | echo >&2 "Trivially automerged." |
152 | else | |
153 | git merge-index -o git-merge-one-file -a | |
19205acf | 154 | fi |
1be0659e JH |
155 | |
156 | # Do not register the cleanly merged paths in the index yet. | |
157 | # this is not a real merge before committing, but just carrying | |
158 | # the working tree changes along. | |
159 | unmerged=`git ls-files -u` | |
160 | git read-tree --reset $new | |
161 | case "$unmerged" in | |
162 | '') ;; | |
163 | *) | |
164 | ( | |
165 | z40=0000000000000000000000000000000000000000 | |
166 | echo "$unmerged" | | |
167 | sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" | |
168 | echo "$unmerged" | |
169 | ) | git update-index --index-info | |
170 | ;; | |
171 | esac | |
172 | exit 0 | |
19205acf | 173 | ) |
980d8ce5 | 174 | saved_err=$? |
504fe714 JH |
175 | if test "$saved_err" = 0 |
176 | then | |
177 | test "$new" = "$old" || git diff-index --name-status "$new" | |
178 | fi | |
980d8ce5 | 179 | (exit $saved_err) |
ef0bfa25 LT |
180 | fi |
181 | ||
182 | # | |
01385e27 | 183 | # Switch the HEAD pointer to the new branch if we |
ef0bfa25 LT |
184 | # checked out a branch head, and remove any potential |
185 | # old MERGE_HEAD's (subsequent commits will clearly not | |
186 | # be based on them, since we re-set the index) | |
187 | # | |
188 | if [ "$?" -eq 0 ]; then | |
91dcdfd3 | 189 | if [ "$newbranch" ]; then |
13d1cc36 JH |
190 | leading=`expr "refs/heads/$newbranch" : '\(.*\)/'` && |
191 | mkdir -p "$GIT_DIR/$leading" && | |
192 | echo $new >"$GIT_DIR/refs/heads/$newbranch" || exit | |
91dcdfd3 LT |
193 | branch="$newbranch" |
194 | fi | |
8098a178 JH |
195 | [ "$branch" ] && |
196 | GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch" | |
ef0bfa25 | 197 | rm -f "$GIT_DIR/MERGE_HEAD" |
ab22707f TL |
198 | else |
199 | exit 1 | |
ef0bfa25 | 200 | fi |