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