]>
Commit | Line | Data |
---|---|---|
1 | #!/bin/sh | |
2 | ||
3 | test_description='checkout' | |
4 | ||
5 | . ./test-lib.sh | |
6 | ||
7 | # Arguments: [!] <branch> <oid> [<checkout options>] | |
8 | # | |
9 | # Runs "git checkout" to switch to <branch>, testing that | |
10 | # | |
11 | # 1) we are on the specified branch, <branch>; | |
12 | # 2) HEAD is <oid>; if <oid> is not specified, the old HEAD is used. | |
13 | # | |
14 | # If <checkout options> is not specified, "git checkout" is run with -b. | |
15 | # | |
16 | # If the first argument is `!`, "git checkout" is expected to fail when | |
17 | # it is run. | |
18 | do_checkout () { | |
19 | should_fail= && | |
20 | if test "x$1" = "x!" | |
21 | then | |
22 | should_fail=yes && | |
23 | shift | |
24 | fi && | |
25 | exp_branch=$1 && | |
26 | exp_ref="refs/heads/$exp_branch" && | |
27 | ||
28 | # if <oid> is not specified, use HEAD. | |
29 | exp_oid=${2:-$(git rev-parse --verify HEAD)} && | |
30 | ||
31 | # default options for git checkout: -b | |
32 | if test -z "$3" | |
33 | then | |
34 | opts="-b" | |
35 | else | |
36 | opts="$3" | |
37 | fi | |
38 | ||
39 | if test -n "$should_fail" | |
40 | then | |
41 | test_must_fail git checkout $opts $exp_branch $exp_oid | |
42 | else | |
43 | git checkout $opts $exp_branch $exp_oid && | |
44 | echo "$exp_ref" >ref.expect && | |
45 | git rev-parse --symbolic-full-name HEAD >ref.actual && | |
46 | test_cmp ref.expect ref.actual && | |
47 | echo "$exp_oid" >oid.expect && | |
48 | git rev-parse --verify HEAD >oid.actual && | |
49 | test_cmp oid.expect oid.actual | |
50 | fi | |
51 | } | |
52 | ||
53 | test_dirty_unmergeable () { | |
54 | test_expect_code 1 git diff --exit-code | |
55 | } | |
56 | ||
57 | test_dirty_unmergeable_discards_changes () { | |
58 | git diff --exit-code | |
59 | } | |
60 | ||
61 | setup_dirty_unmergeable () { | |
62 | echo >>file1 change2 | |
63 | } | |
64 | ||
65 | test_dirty_mergeable () { | |
66 | test_expect_code 1 git diff --cached --exit-code | |
67 | } | |
68 | ||
69 | test_dirty_mergeable_discards_changes () { | |
70 | git diff --cached --exit-code | |
71 | } | |
72 | ||
73 | setup_dirty_mergeable () { | |
74 | echo >file2 file2 && | |
75 | git add file2 | |
76 | } | |
77 | ||
78 | test_expect_success 'setup' ' | |
79 | test_commit initial file1 && | |
80 | HEAD1=$(git rev-parse --verify HEAD) && | |
81 | ||
82 | test_commit change1 file1 && | |
83 | HEAD2=$(git rev-parse --verify HEAD) && | |
84 | ||
85 | git branch -m branch1 | |
86 | ' | |
87 | ||
88 | test_expect_success 'checkout -b to a new branch, set to HEAD' ' | |
89 | test_when_finished " | |
90 | git checkout branch1 && | |
91 | test_might_fail git branch -D branch2" && | |
92 | do_checkout branch2 | |
93 | ' | |
94 | ||
95 | test_expect_success 'checkout -b to a merge base' ' | |
96 | test_when_finished " | |
97 | git checkout branch1 && | |
98 | test_might_fail git branch -D branch2" && | |
99 | git checkout -b branch2 branch1... | |
100 | ' | |
101 | ||
102 | test_expect_success 'checkout -b to a new branch, set to an explicit ref' ' | |
103 | test_when_finished " | |
104 | git checkout branch1 && | |
105 | test_might_fail git branch -D branch2" && | |
106 | do_checkout branch2 $HEAD1 | |
107 | ' | |
108 | ||
109 | test_expect_success 'checkout -b to a new branch with unmergeable changes fails' ' | |
110 | setup_dirty_unmergeable && | |
111 | do_checkout ! branch2 $HEAD1 && | |
112 | test_dirty_unmergeable | |
113 | ' | |
114 | ||
115 | test_expect_success 'checkout -f -b to a new branch with unmergeable changes discards changes' ' | |
116 | test_when_finished " | |
117 | git checkout branch1 && | |
118 | test_might_fail git branch -D branch2" && | |
119 | ||
120 | # still dirty and on branch1 | |
121 | do_checkout branch2 $HEAD1 "-f -b" && | |
122 | test_dirty_unmergeable_discards_changes | |
123 | ' | |
124 | ||
125 | test_expect_success 'checkout -b to a new branch preserves mergeable changes' ' | |
126 | test_when_finished " | |
127 | git reset --hard && | |
128 | git checkout branch1 && | |
129 | test_might_fail git branch -D branch2" && | |
130 | ||
131 | setup_dirty_mergeable && | |
132 | do_checkout branch2 $HEAD1 && | |
133 | test_dirty_mergeable | |
134 | ' | |
135 | ||
136 | test_expect_success 'checkout -f -b to a new branch with mergeable changes discards changes' ' | |
137 | test_when_finished git reset --hard HEAD && | |
138 | setup_dirty_mergeable && | |
139 | do_checkout branch2 $HEAD1 "-f -b" && | |
140 | test_dirty_mergeable_discards_changes | |
141 | ' | |
142 | ||
143 | test_expect_success 'checkout -b to an existing branch fails' ' | |
144 | test_when_finished git reset --hard HEAD && | |
145 | do_checkout ! branch2 $HEAD2 | |
146 | ' | |
147 | ||
148 | test_expect_success 'checkout -b to @{-1} fails with the right branch name' ' | |
149 | git checkout branch1 && | |
150 | git checkout branch2 && | |
151 | echo >expect "fatal: A branch named '\''branch1'\'' already exists." && | |
152 | test_must_fail git checkout -b @{-1} 2>actual && | |
153 | test_i18ncmp expect actual | |
154 | ' | |
155 | ||
156 | test_expect_success 'checkout -B to an existing branch resets branch to HEAD' ' | |
157 | git checkout branch1 && | |
158 | ||
159 | do_checkout branch2 "" -B | |
160 | ' | |
161 | ||
162 | test_expect_success 'checkout -B to a merge base' ' | |
163 | git checkout branch1 && | |
164 | ||
165 | git checkout -B branch2 branch1... | |
166 | ' | |
167 | ||
168 | test_expect_success 'checkout -B to an existing branch from detached HEAD resets branch to HEAD' ' | |
169 | head=$(git rev-parse --verify HEAD) && | |
170 | git checkout "$head" && | |
171 | ||
172 | do_checkout branch2 "" -B | |
173 | ' | |
174 | ||
175 | test_expect_success 'checkout -B to an existing branch with an explicit ref resets branch to that ref' ' | |
176 | git checkout branch1 && | |
177 | ||
178 | do_checkout branch2 $HEAD1 -B | |
179 | ' | |
180 | ||
181 | test_expect_success 'checkout -B to an existing branch with unmergeable changes fails' ' | |
182 | git checkout branch1 && | |
183 | ||
184 | setup_dirty_unmergeable && | |
185 | do_checkout ! branch2 $HEAD1 -B && | |
186 | test_dirty_unmergeable | |
187 | ' | |
188 | ||
189 | test_expect_success 'checkout -f -B to an existing branch with unmergeable changes discards changes' ' | |
190 | # still dirty and on branch1 | |
191 | do_checkout branch2 $HEAD1 "-f -B" && | |
192 | test_dirty_unmergeable_discards_changes | |
193 | ' | |
194 | ||
195 | test_expect_success 'checkout -B to an existing branch preserves mergeable changes' ' | |
196 | test_when_finished git reset --hard && | |
197 | git checkout branch1 && | |
198 | ||
199 | setup_dirty_mergeable && | |
200 | do_checkout branch2 $HEAD1 -B && | |
201 | test_dirty_mergeable | |
202 | ' | |
203 | ||
204 | test_expect_success 'checkout -f -B to an existing branch with mergeable changes discards changes' ' | |
205 | git checkout branch1 && | |
206 | ||
207 | setup_dirty_mergeable && | |
208 | do_checkout branch2 $HEAD1 "-f -B" && | |
209 | test_dirty_mergeable_discards_changes | |
210 | ' | |
211 | ||
212 | test_expect_success 'checkout -b <describe>' ' | |
213 | git tag -f -m "First commit" initial initial && | |
214 | git checkout -f change1 && | |
215 | name=$(git describe) && | |
216 | git checkout -b $name && | |
217 | git diff --exit-code change1 && | |
218 | echo "refs/heads/$name" >expect && | |
219 | git symbolic-ref HEAD >actual && | |
220 | test_cmp expect actual | |
221 | ' | |
222 | ||
223 | test_expect_success 'checkout -B to the current branch works' ' | |
224 | git checkout branch1 && | |
225 | git checkout -B branch1-scratch && | |
226 | ||
227 | setup_dirty_mergeable && | |
228 | git checkout -B branch1-scratch initial && | |
229 | test_dirty_mergeable | |
230 | ' | |
231 | ||
232 | test_expect_success 'checkout -b after clone --no-checkout does a checkout of HEAD' ' | |
233 | git init src && | |
234 | test_commit -C src a && | |
235 | rev="$(git -C src rev-parse HEAD)" && | |
236 | git clone --no-checkout src dest && | |
237 | git -C dest checkout "$rev" -b branch && | |
238 | test_path_is_file dest/a.t | |
239 | ' | |
240 | ||
241 | test_expect_success 'checkout -b to a new branch preserves mergeable changes despite sparse-checkout' ' | |
242 | test_when_finished " | |
243 | git reset --hard && | |
244 | git checkout branch1-scratch && | |
245 | test_might_fail git branch -D branch3 && | |
246 | git config core.sparseCheckout false && | |
247 | rm .git/info/sparse-checkout" && | |
248 | ||
249 | test_commit file2 && | |
250 | ||
251 | echo stuff >>file1 && | |
252 | echo file2 >.git/info/sparse-checkout && | |
253 | git config core.sparseCheckout true && | |
254 | ||
255 | CURHEAD=$(git rev-parse HEAD) && | |
256 | do_checkout branch3 $CURHEAD && | |
257 | ||
258 | echo file1 >expect && | |
259 | git diff --name-only >actual && | |
260 | test_cmp expect actual | |
261 | ' | |
262 | ||
263 | test_expect_success 'checkout -b rejects an invalid start point' ' | |
264 | test_must_fail git checkout -b branch4 file1 2>err && | |
265 | test_i18ngrep "is not a commit" err | |
266 | ' | |
267 | ||
268 | test_expect_success 'checkout -b rejects an extra path argument' ' | |
269 | test_must_fail git checkout -b branch5 branch1 file1 2>err && | |
270 | test_i18ngrep "Cannot update paths and switch to branch" err | |
271 | ' | |
272 | ||
273 | test_done |