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