1 #!/bin/sh
3 test_description='test aborting in-progress merges
5 Set up repo with conflicting and non-conflicting branches:
7 There are three files foo/bar/baz, and the following graph illustrates the
8 content of these files in each commit:
10 # foo/bar/baz --- foo/bar/bazz <-- master
11 # \
12 # --- foo/barf/bazf <-- conflict_branch
13 # \
14 # --- foo/bart/baz <-- clean_branch
16 Next, test git merge --abort with the following variables:
17 - before/after successful merge (should fail when not in merge context)
18 - with/without conflicts
19 - clean/dirty index before merge
20 - clean/dirty worktree before merge
21 - dirty index before merge matches contents on remote branch
22 - changed/unchanged worktree after merge
23 - changed/unchanged index after merge
24 '
25 . ./test-lib.sh
27 test_expect_success 'setup' '
28 # Create the above repo
29 echo foo > foo &&
30 echo bar > bar &&
31 echo baz > baz &&
32 git add foo bar baz &&
33 git commit -m initial &&
34 echo bazz > baz &&
35 git commit -a -m "second" &&
36 git checkout -b conflict_branch HEAD^ &&
37 echo barf > bar &&
38 echo bazf > baz &&
39 git commit -a -m "conflict" &&
40 git checkout -b clean_branch HEAD^ &&
41 echo bart > bar &&
42 git commit -a -m "clean" &&
43 git checkout master
44 '
46 pre_merge_head="$(git rev-parse HEAD)"
48 test_expect_success 'fails without MERGE_HEAD (unstarted merge)' '
49 test_must_fail git merge --abort 2>output
50 '
52 test_expect_success C_LOCALE_OUTPUT 'fails without MERGE_HEAD (unstarted merge): fatal output' '
53 grep -q MERGE_HEAD output
54 '
56 test_expect_success 'fails without MERGE_HEAD (unstarted merge): .git/MERGE_HEAD sanity' '
57 test ! -f .git/MERGE_HEAD &&
58 test "$pre_merge_head" = "$(git rev-parse HEAD)"
59 '
61 test_expect_success 'fails without MERGE_HEAD (completed merge)' '
62 git merge clean_branch &&
63 test ! -f .git/MERGE_HEAD &&
64 # Merge successfully completed
65 post_merge_head="$(git rev-parse HEAD)" &&
66 test_must_fail git merge --abort 2>output
67 '
69 test_expect_success C_LOCALE_OUTPUT 'fails without MERGE_HEAD (completed merge): output' '
70 grep -q MERGE_HEAD output
71 '
73 test_expect_success 'fails without MERGE_HEAD (completed merge): .git/MERGE_HEAD sanity' '
74 test ! -f .git/MERGE_HEAD &&
75 test "$post_merge_head" = "$(git rev-parse HEAD)"
76 '
78 test_expect_success 'Forget previous merge' '
79 git reset --hard "$pre_merge_head"
80 '
82 test_expect_success 'Abort after --no-commit' '
83 # Redo merge, but stop before creating merge commit
84 git merge --no-commit clean_branch &&
85 test -f .git/MERGE_HEAD &&
86 # Abort non-conflicting merge
87 git merge --abort &&
88 test ! -f .git/MERGE_HEAD &&
89 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
90 test -z "$(git diff)" &&
91 test -z "$(git diff --staged)"
92 '
94 test_expect_success 'Abort after conflicts' '
95 # Create conflicting merge
96 test_must_fail git merge conflict_branch &&
97 test -f .git/MERGE_HEAD &&
98 # Abort conflicting merge
99 git merge --abort &&
100 test ! -f .git/MERGE_HEAD &&
101 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
102 test -z "$(git diff)" &&
103 test -z "$(git diff --staged)"
104 '
106 test_expect_success 'Clean merge with dirty index fails' '
107 echo xyzzy >> foo &&
108 git add foo &&
109 git diff --staged > expect &&
110 test_must_fail git merge clean_branch &&
111 test ! -f .git/MERGE_HEAD &&
112 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
113 test -z "$(git diff)" &&
114 git diff --staged > actual &&
115 test_cmp expect actual
116 '
118 test_expect_success 'Conflicting merge with dirty index fails' '
119 test_must_fail git merge conflict_branch &&
120 test ! -f .git/MERGE_HEAD &&
121 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
122 test -z "$(git diff)" &&
123 git diff --staged > actual &&
124 test_cmp expect actual
125 '
127 test_expect_success 'Reset index (but preserve worktree changes)' '
128 git reset "$pre_merge_head" &&
129 git diff > actual &&
130 test_cmp expect actual
131 '
133 test_expect_success 'Abort clean merge with non-conflicting dirty worktree' '
134 git merge --no-commit clean_branch &&
135 test -f .git/MERGE_HEAD &&
136 # Abort merge
137 git merge --abort &&
138 test ! -f .git/MERGE_HEAD &&
139 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
140 test -z "$(git diff --staged)" &&
141 git diff > actual &&
142 test_cmp expect actual
143 '
145 test_expect_success 'Abort conflicting merge with non-conflicting dirty worktree' '
146 test_must_fail git merge conflict_branch &&
147 test -f .git/MERGE_HEAD &&
148 # Abort merge
149 git merge --abort &&
150 test ! -f .git/MERGE_HEAD &&
151 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
152 test -z "$(git diff --staged)" &&
153 git diff > actual &&
154 test_cmp expect actual
155 '
157 test_expect_success 'Reset worktree changes' '
158 git reset --hard "$pre_merge_head"
159 '
161 test_expect_success 'Fail clean merge with conflicting dirty worktree' '
162 echo xyzzy >> bar &&
163 git diff > expect &&
164 test_must_fail git merge --no-commit clean_branch &&
165 test ! -f .git/MERGE_HEAD &&
166 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
167 test -z "$(git diff --staged)" &&
168 git diff > actual &&
169 test_cmp expect actual
170 '
172 test_expect_success 'Fail conflicting merge with conflicting dirty worktree' '
173 test_must_fail git merge conflict_branch &&
174 test ! -f .git/MERGE_HEAD &&
175 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
176 test -z "$(git diff --staged)" &&
177 git diff > actual &&
178 test_cmp expect actual
179 '
181 test_expect_success 'Reset worktree changes' '
182 git reset --hard "$pre_merge_head"
183 '
185 test_expect_success 'Fail clean merge with matching dirty worktree' '
186 echo bart > bar &&
187 git diff > expect &&
188 test_must_fail git merge --no-commit clean_branch &&
189 test ! -f .git/MERGE_HEAD &&
190 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
191 test -z "$(git diff --staged)" &&
192 git diff > actual &&
193 test_cmp expect actual
194 '
196 test_expect_success 'Abort clean merge with matching dirty index' '
197 git add bar &&
198 git diff --staged > expect &&
199 git merge --no-commit clean_branch &&
200 test -f .git/MERGE_HEAD &&
201 ### When aborting the merge, git will discard all staged changes,
202 ### including those that were staged pre-merge. In other words,
203 ### --abort will LOSE any staged changes (the staged changes that
204 ### are lost must match the merge result, or the merge would not
205 ### have been allowed to start). Change expectations accordingly:
206 rm expect &&
207 touch expect &&
208 # Abort merge
209 git merge --abort &&
210 test ! -f .git/MERGE_HEAD &&
211 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
212 git diff --staged > actual &&
213 test_cmp expect actual &&
214 test -z "$(git diff)"
215 '
217 test_expect_success 'Reset worktree changes' '
218 git reset --hard "$pre_merge_head"
219 '
221 test_expect_success 'Fail conflicting merge with matching dirty worktree' '
222 echo barf > bar &&
223 git diff > expect &&
224 test_must_fail git merge conflict_branch &&
225 test ! -f .git/MERGE_HEAD &&
226 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
227 test -z "$(git diff --staged)" &&
228 git diff > actual &&
229 test_cmp expect actual
230 '
232 test_expect_success 'Abort conflicting merge with matching dirty index' '
233 git add bar &&
234 git diff --staged > expect &&
235 test_must_fail git merge conflict_branch &&
236 test -f .git/MERGE_HEAD &&
237 ### When aborting the merge, git will discard all staged changes,
238 ### including those that were staged pre-merge. In other words,
239 ### --abort will LOSE any staged changes (the staged changes that
240 ### are lost must match the merge result, or the merge would not
241 ### have been allowed to start). Change expectations accordingly:
242 rm expect &&
243 touch expect &&
244 # Abort merge
245 git merge --abort &&
246 test ! -f .git/MERGE_HEAD &&
247 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
248 git diff --staged > actual &&
249 test_cmp expect actual &&
250 test -z "$(git diff)"
251 '
253 test_expect_success 'Reset worktree changes' '
254 git reset --hard "$pre_merge_head"
255 '
257 test_expect_success 'Abort merge with pre- and post-merge worktree changes' '
258 # Pre-merge worktree changes
259 echo xyzzy > foo &&
260 echo barf > bar &&
261 git add bar &&
262 git diff > expect &&
263 git diff --staged > expect-staged &&
264 # Perform merge
265 test_must_fail git merge conflict_branch &&
266 test -f .git/MERGE_HEAD &&
267 # Post-merge worktree changes
268 echo yzxxz > foo &&
269 echo blech > baz &&
270 ### When aborting the merge, git will discard staged changes (bar)
271 ### and unmerged changes (baz). Other changes that are neither
272 ### staged nor marked as unmerged (foo), will be preserved. For
273 ### these changed, git cannot tell pre-merge changes apart from
274 ### post-merge changes, so the post-merge changes will be
275 ### preserved. Change expectations accordingly:
276 git diff -- foo > expect &&
277 rm expect-staged &&
278 touch expect-staged &&
279 # Abort merge
280 git merge --abort &&
281 test ! -f .git/MERGE_HEAD &&
282 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
283 git diff > actual &&
284 test_cmp expect actual &&
285 git diff --staged > actual-staged &&
286 test_cmp expect-staged actual-staged
287 '
289 test_expect_success 'Reset worktree changes' '
290 git reset --hard "$pre_merge_head"
291 '
293 test_expect_success 'Abort merge with pre- and post-merge index changes' '
294 # Pre-merge worktree changes
295 echo xyzzy > foo &&
296 echo barf > bar &&
297 git add bar &&
298 git diff > expect &&
299 git diff --staged > expect-staged &&
300 # Perform merge
301 test_must_fail git merge conflict_branch &&
302 test -f .git/MERGE_HEAD &&
303 # Post-merge worktree changes
304 echo yzxxz > foo &&
305 echo blech > baz &&
306 git add foo bar &&
307 ### When aborting the merge, git will discard all staged changes
308 ### (foo, bar and baz), and no changes will be preserved. Whether
309 ### the changes were staged pre- or post-merge does not matter
310 ### (except for not preventing starting the merge).
311 ### Change expectations accordingly:
312 rm expect expect-staged &&
313 touch expect &&
314 touch expect-staged &&
315 # Abort merge
316 git merge --abort &&
317 test ! -f .git/MERGE_HEAD &&
318 test "$pre_merge_head" = "$(git rev-parse HEAD)" &&
319 git diff > actual &&
320 test_cmp expect actual &&
321 git diff --staged > actual-staged &&
322 test_cmp expect-staged actual-staged
323 '
325 test_done