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 grep -q MERGE_HEAD output &&
51 test ! -f .git/MERGE_HEAD &&
52 test "$pre_merge_head" = "$(git rev-parse HEAD)"
53'
54
55test_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
66test_expect_success 'Forget previous merge' '
67 git reset --hard "$pre_merge_head"
68'
69
70test_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
82test_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
94test_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
106test_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
115test_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
121test_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
133test_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
145test_expect_success 'Reset worktree changes' '
146 git reset --hard "$pre_merge_head"
147'
148
149test_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
160test_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
169test_expect_success 'Reset worktree changes' '
170 git reset --hard "$pre_merge_head"
171'
172
173test_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
184test_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
205test_expect_success 'Reset worktree changes' '
206 git reset --hard "$pre_merge_head"
207'
208
209test_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
220test_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
241test_expect_success 'Reset worktree changes' '
242 git reset --hard "$pre_merge_head"
243'
244
245test_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
277test_expect_success 'Reset worktree changes' '
278 git reset --hard "$pre_merge_head"
279'
280
281test_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
313test_done