]>
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 JH |
24 | git-check-ref-format "heads/$newbranch" || |
25 | die "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 | |
1be0659e | 78 | if test '' != "$newbranch$force$merge" |
4aaa7027 JH |
79 | then |
80 | die "updating paths and switching branches or forcing are incompatible." | |
81 | fi | |
82 | if test '' != "$new" | |
83 | then | |
84 | # from a specific tree-ish; note that this is for | |
85 | # rescuing paths and is never meant to remove what | |
86 | # is not in the named tree-ish. | |
d0d14cf3 | 87 | git-ls-tree --full-name -r "$new" "$@" | |
4aaa7027 JH |
88 | git-update-index --index-info || exit $? |
89 | fi | |
90 | git-checkout-index -f -u -- "$@" | |
91 | exit $? | |
92 | else | |
93 | # Make sure we did not fall back on $arg^{tree} codepath | |
94 | # since we are not checking out from an arbitrary tree-ish, | |
95 | # but switching branches. | |
96 | if test '' != "$new" | |
97 | then | |
98 | git-rev-parse --verify "$new^{commit}" >/dev/null 2>&1 || | |
99 | die "Cannot switch branch to a non-commit." | |
100 | fi | |
101 | fi | |
102 | ||
104f3e03 JH |
103 | # We are switching branches and checking out trees, so |
104 | # we *NEED* to be at the toplevel. | |
105 | cdup=$(git-rev-parse --show-cdup) | |
106 | if test ! -z "$cdup" | |
107 | then | |
108 | cd "$cdup" | |
109 | fi | |
110 | ||
4aaa7027 JH |
111 | [ -z "$new" ] && new=$old |
112 | ||
91dcdfd3 LT |
113 | # If we don't have an old branch that we're switching to, |
114 | # and we don't have a new branch name for the target we | |
115 | # are switching to, then we'd better just be checking out | |
116 | # what we already had | |
4aaa7027 | 117 | |
91dcdfd3 LT |
118 | [ -z "$branch$newbranch" ] && |
119 | [ "$new" != "$old" ] && | |
120 | die "git checkout: you need to specify a new branch name" | |
121 | ||
a79944d7 | 122 | if [ "$force" ] |
303e5f4c LT |
123 | then |
124 | git-read-tree --reset $new && | |
215a7ad1 | 125 | git-checkout-index -q -f -u -a |
303e5f4c | 126 | else |
7f88c846 | 127 | git-update-index --refresh >/dev/null |
1be0659e JH |
128 | merge_error=$(git-read-tree -m -u $old $new 2>&1) || ( |
129 | case "$merge" in | |
130 | '') | |
131 | echo >&2 "$merge_error" | |
132 | exit 1 ;; | |
19205acf JH |
133 | esac |
134 | ||
1be0659e JH |
135 | # Match the index to the working tree, and do a three-way. |
136 | git diff-files --name-only | git update-index --remove --stdin && | |
19205acf | 137 | work=`git write-tree` && |
1be0659e JH |
138 | git read-tree --reset $new && |
139 | git checkout-index -f -u -q -a && | |
140 | git read-tree -m -u $old $new $work || exit | |
141 | ||
19205acf JH |
142 | if result=`git write-tree 2>/dev/null` |
143 | then | |
1be0659e JH |
144 | echo >&2 "Trivially automerged." |
145 | else | |
146 | git merge-index -o git-merge-one-file -a | |
19205acf | 147 | fi |
1be0659e JH |
148 | |
149 | # Do not register the cleanly merged paths in the index yet. | |
150 | # this is not a real merge before committing, but just carrying | |
151 | # the working tree changes along. | |
152 | unmerged=`git ls-files -u` | |
153 | git read-tree --reset $new | |
154 | case "$unmerged" in | |
155 | '') ;; | |
156 | *) | |
157 | ( | |
158 | z40=0000000000000000000000000000000000000000 | |
159 | echo "$unmerged" | | |
160 | sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /" | |
161 | echo "$unmerged" | |
162 | ) | git update-index --index-info | |
163 | ;; | |
164 | esac | |
165 | exit 0 | |
19205acf | 166 | ) |
980d8ce5 JH |
167 | saved_err=$? |
168 | git diff-files --name-status | |
169 | (exit $saved_err) | |
ef0bfa25 LT |
170 | fi |
171 | ||
172 | # | |
01385e27 | 173 | # Switch the HEAD pointer to the new branch if we |
ef0bfa25 LT |
174 | # checked out a branch head, and remove any potential |
175 | # old MERGE_HEAD's (subsequent commits will clearly not | |
176 | # be based on them, since we re-set the index) | |
177 | # | |
178 | if [ "$?" -eq 0 ]; then | |
91dcdfd3 | 179 | if [ "$newbranch" ]; then |
13d1cc36 JH |
180 | leading=`expr "refs/heads/$newbranch" : '\(.*\)/'` && |
181 | mkdir -p "$GIT_DIR/$leading" && | |
182 | echo $new >"$GIT_DIR/refs/heads/$newbranch" || exit | |
91dcdfd3 LT |
183 | branch="$newbranch" |
184 | fi | |
8098a178 JH |
185 | [ "$branch" ] && |
186 | GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD "refs/heads/$branch" | |
ef0bfa25 | 187 | rm -f "$GIT_DIR/MERGE_HEAD" |
ab22707f TL |
188 | else |
189 | exit 1 | |
ef0bfa25 | 190 | fi |