Merge branch 'ld/p4-cleanup-processes'
[git] / t / t3310-notes-merge-manual-resolve.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2010 Johan Herland
4 #
5
6 test_description='Test notes merging with manual conflict resolution'
7
8 . ./test-lib.sh
9
10 # Set up a notes merge scenario with different kinds of conflicts
11 test_expect_success 'setup commits' '
12         test_commit 1st &&
13         test_commit 2nd &&
14         test_commit 3rd &&
15         test_commit 4th &&
16         test_commit 5th
17 '
18
19 commit_sha1=$(git rev-parse 1st^{commit})
20 commit_sha2=$(git rev-parse 2nd^{commit})
21 commit_sha3=$(git rev-parse 3rd^{commit})
22 commit_sha4=$(git rev-parse 4th^{commit})
23 commit_sha5=$(git rev-parse 5th^{commit})
24
25 verify_notes () {
26         notes_ref="$1"
27         git -c core.notesRef="refs/notes/$notes_ref" notes |
28                 sort >"output_notes_$notes_ref" &&
29         test_cmp "expect_notes_$notes_ref" "output_notes_$notes_ref" &&
30         git -c core.notesRef="refs/notes/$notes_ref" log --format="%H %s%n%N" \
31                 >"output_log_$notes_ref" &&
32         test_cmp "expect_log_$notes_ref" "output_log_$notes_ref"
33 }
34
35 notes_merge_files_gone () {
36         # No .git/NOTES_MERGE_* files left
37         { ls .git/NOTES_MERGE_* >output || :; } &&
38         test_must_be_empty output
39 }
40
41 cat <<EOF | sort >expect_notes_x
42 6e8e3febca3c2bb896704335cc4d0c34cb2f8715 $commit_sha4
43 e5388c10860456ee60673025345fe2e153eb8cf8 $commit_sha3
44 ceefa674873670e7ecd131814d909723cce2b669 $commit_sha2
45 EOF
46
47 cat >expect_log_x <<EOF
48 $commit_sha5 5th
49
50 $commit_sha4 4th
51 x notes on 4th commit
52
53 $commit_sha3 3rd
54 x notes on 3rd commit
55
56 $commit_sha2 2nd
57 x notes on 2nd commit
58
59 $commit_sha1 1st
60
61 EOF
62
63 test_expect_success 'setup merge base (x)' '
64         git config core.notesRef refs/notes/x &&
65         git notes add -m "x notes on 2nd commit" 2nd &&
66         git notes add -m "x notes on 3rd commit" 3rd &&
67         git notes add -m "x notes on 4th commit" 4th &&
68         verify_notes x
69 '
70
71 cat <<EOF | sort >expect_notes_y
72 e2bfd06a37dd2031684a59a6e2b033e212239c78 $commit_sha4
73 5772f42408c0dd6f097a7ca2d24de0e78d1c46b1 $commit_sha3
74 b0a6021ec006d07e80e9b20ec9b444cbd9d560d3 $commit_sha1
75 EOF
76
77 cat >expect_log_y <<EOF
78 $commit_sha5 5th
79
80 $commit_sha4 4th
81 y notes on 4th commit
82
83 $commit_sha3 3rd
84 y notes on 3rd commit
85
86 $commit_sha2 2nd
87
88 $commit_sha1 1st
89 y notes on 1st commit
90
91 EOF
92
93 test_expect_success 'setup local branch (y)' '
94         git update-ref refs/notes/y refs/notes/x &&
95         git config core.notesRef refs/notes/y &&
96         git notes add -f -m "y notes on 1st commit" 1st &&
97         git notes remove 2nd &&
98         git notes add -f -m "y notes on 3rd commit" 3rd &&
99         git notes add -f -m "y notes on 4th commit" 4th &&
100         verify_notes y
101 '
102
103 cat <<EOF | sort >expect_notes_z
104 cff59c793c20bb49a4e01bc06fb06bad642e0d54 $commit_sha4
105 283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
106 0a81da8956346e19bcb27a906f04af327e03e31b $commit_sha1
107 EOF
108
109 cat >expect_log_z <<EOF
110 $commit_sha5 5th
111
112 $commit_sha4 4th
113 z notes on 4th commit
114
115 $commit_sha3 3rd
116
117 $commit_sha2 2nd
118 z notes on 2nd commit
119
120 $commit_sha1 1st
121 z notes on 1st commit
122
123 EOF
124
125 test_expect_success 'setup remote branch (z)' '
126         git update-ref refs/notes/z refs/notes/x &&
127         git config core.notesRef refs/notes/z &&
128         git notes add -f -m "z notes on 1st commit" 1st &&
129         git notes add -f -m "z notes on 2nd commit" 2nd &&
130         git notes remove 3rd &&
131         git notes add -f -m "z notes on 4th commit" 4th &&
132         verify_notes z
133 '
134
135 # At this point, before merging z into y, we have the following status:
136 #
137 # commit | base/x  | local/y | remote/z | diff from x to y/z
138 # -------|---------|---------|----------|---------------------------
139 # 1st    | [none]  | b0a6021 | 0a81da8  | added     / added (diff)
140 # 2nd    | ceefa67 | [none]  | 283b482  | removed   / changed
141 # 3rd    | e5388c1 | 5772f42 | [none]   | changed   / removed
142 # 4th    | 6e8e3fe | e2bfd06 | cff59c7  | changed   / changed (diff)
143 # 5th    | [none]  | [none]  | [none]   | [none]
144
145 cat <<EOF | sort >expect_conflicts
146 $commit_sha1
147 $commit_sha2
148 $commit_sha3
149 $commit_sha4
150 EOF
151
152 cat >expect_conflict_$commit_sha1 <<EOF
153 <<<<<<< refs/notes/m
154 y notes on 1st commit
155 =======
156 z notes on 1st commit
157 >>>>>>> refs/notes/z
158 EOF
159
160 cat >expect_conflict_$commit_sha2 <<EOF
161 z notes on 2nd commit
162 EOF
163
164 cat >expect_conflict_$commit_sha3 <<EOF
165 y notes on 3rd commit
166 EOF
167
168 cat >expect_conflict_$commit_sha4 <<EOF
169 <<<<<<< refs/notes/m
170 y notes on 4th commit
171 =======
172 z notes on 4th commit
173 >>>>>>> refs/notes/z
174 EOF
175
176 cp expect_notes_y expect_notes_m
177 cp expect_log_y expect_log_m
178
179 git rev-parse refs/notes/y > pre_merge_y
180 git rev-parse refs/notes/z > pre_merge_z
181
182 test_expect_success 'merge z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
183         git update-ref refs/notes/m refs/notes/y &&
184         git config core.notesRef refs/notes/m &&
185         test_must_fail git notes merge z >output 2>&1 &&
186         # Output should point to where to resolve conflicts
187         test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
188         # Inspect merge conflicts
189         ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
190         test_cmp expect_conflicts output_conflicts &&
191         ( for f in $(cat expect_conflicts); do
192                 test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
193                 exit 1
194         done ) &&
195         # Verify that current notes tree (pre-merge) has not changed (m == y)
196         verify_notes y &&
197         verify_notes m &&
198         test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
199 '
200
201 cat <<EOF | sort >expect_notes_z
202 00494adecf2d9635a02fa431308d67993f853968 $commit_sha4
203 283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
204 0a81da8956346e19bcb27a906f04af327e03e31b $commit_sha1
205 EOF
206
207 cat >expect_log_z <<EOF
208 $commit_sha5 5th
209
210 $commit_sha4 4th
211 z notes on 4th commit
212
213 More z notes on 4th commit
214
215 $commit_sha3 3rd
216
217 $commit_sha2 2nd
218 z notes on 2nd commit
219
220 $commit_sha1 1st
221 z notes on 1st commit
222
223 EOF
224
225 test_expect_success 'change notes in z' '
226         git notes --ref z append -m "More z notes on 4th commit" 4th &&
227         verify_notes z
228 '
229
230 test_expect_success 'cannot do merge w/conflicts when previous merge is unfinished' '
231         test -d .git/NOTES_MERGE_WORKTREE &&
232         test_must_fail git notes merge z >output 2>&1 &&
233         # Output should indicate what is wrong
234         test_i18ngrep -q "\\.git/NOTES_MERGE_\\* exists" output
235 '
236
237 # Setup non-conflicting merge between x and new notes ref w
238
239 cat <<EOF | sort >expect_notes_w
240 ceefa674873670e7ecd131814d909723cce2b669 $commit_sha2
241 f75d1df88cbfe4258d49852f26cfc83f2ad4494b $commit_sha1
242 EOF
243
244 cat >expect_log_w <<EOF
245 $commit_sha5 5th
246
247 $commit_sha4 4th
248
249 $commit_sha3 3rd
250
251 $commit_sha2 2nd
252 x notes on 2nd commit
253
254 $commit_sha1 1st
255 w notes on 1st commit
256
257 EOF
258
259 test_expect_success 'setup unrelated notes ref (w)' '
260         git config core.notesRef refs/notes/w &&
261         git notes add -m "w notes on 1st commit" 1st &&
262         git notes add -m "x notes on 2nd commit" 2nd &&
263         verify_notes w
264 '
265
266 cat <<EOF | sort >expect_notes_w
267 6e8e3febca3c2bb896704335cc4d0c34cb2f8715 $commit_sha4
268 e5388c10860456ee60673025345fe2e153eb8cf8 $commit_sha3
269 ceefa674873670e7ecd131814d909723cce2b669 $commit_sha2
270 f75d1df88cbfe4258d49852f26cfc83f2ad4494b $commit_sha1
271 EOF
272
273 cat >expect_log_w <<EOF
274 $commit_sha5 5th
275
276 $commit_sha4 4th
277 x notes on 4th commit
278
279 $commit_sha3 3rd
280 x notes on 3rd commit
281
282 $commit_sha2 2nd
283 x notes on 2nd commit
284
285 $commit_sha1 1st
286 w notes on 1st commit
287
288 EOF
289
290 test_expect_success 'can do merge without conflicts even if previous merge is unfinished (x => w)' '
291         test -d .git/NOTES_MERGE_WORKTREE &&
292         git notes merge x &&
293         verify_notes w &&
294         # Verify that other notes refs has not changed (x and y)
295         verify_notes x &&
296         verify_notes y
297 '
298
299 cat <<EOF | sort >expect_notes_m
300 021faa20e931fb48986ffc6282b4bb05553ac946 $commit_sha4
301 5772f42408c0dd6f097a7ca2d24de0e78d1c46b1 $commit_sha3
302 283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
303 0a59e787e6d688aa6309e56e8c1b89431a0fc1c1 $commit_sha1
304 EOF
305
306 cat >expect_log_m <<EOF
307 $commit_sha5 5th
308
309 $commit_sha4 4th
310 y and z notes on 4th commit
311
312 $commit_sha3 3rd
313 y notes on 3rd commit
314
315 $commit_sha2 2nd
316 z notes on 2nd commit
317
318 $commit_sha1 1st
319 y and z notes on 1st commit
320
321 EOF
322
323 test_expect_success 'do not allow mixing --commit and --abort' '
324         test_must_fail git notes merge --commit --abort
325 '
326
327 test_expect_success 'do not allow mixing --commit and --strategy' '
328         test_must_fail git notes merge --commit --strategy theirs
329 '
330
331 test_expect_success 'do not allow mixing --abort and --strategy' '
332         test_must_fail git notes merge --abort --strategy theirs
333 '
334
335 test_expect_success 'finalize conflicting merge (z => m)' '
336         # Resolve conflicts and finalize merge
337         cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF &&
338 y and z notes on 1st commit
339 EOF
340         cat >.git/NOTES_MERGE_WORKTREE/$commit_sha4 <<EOF &&
341 y and z notes on 4th commit
342 EOF
343         git notes merge --commit &&
344         notes_merge_files_gone &&
345         # Merge commit has pre-merge y and pre-merge z as parents
346         test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
347         test "$(git rev-parse refs/notes/m^2)" = "$(cat pre_merge_z)" &&
348         # Merge commit mentions the notes refs merged
349         git log -1 --format=%B refs/notes/m > merge_commit_msg &&
350         grep -q refs/notes/m merge_commit_msg &&
351         grep -q refs/notes/z merge_commit_msg &&
352         # Merge commit mentions conflicting notes
353         grep -q "Conflicts" merge_commit_msg &&
354         ( for sha1 in $(cat expect_conflicts); do
355                 grep -q "$sha1" merge_commit_msg ||
356                 exit 1
357         done ) &&
358         # Verify contents of merge result
359         verify_notes m &&
360         # Verify that other notes refs has not changed (w, x, y and z)
361         verify_notes w &&
362         verify_notes x &&
363         verify_notes y &&
364         verify_notes z
365 '
366
367 cat >expect_conflict_$commit_sha4 <<EOF
368 <<<<<<< refs/notes/m
369 y notes on 4th commit
370 =======
371 z notes on 4th commit
372
373 More z notes on 4th commit
374 >>>>>>> refs/notes/z
375 EOF
376
377 cp expect_notes_y expect_notes_m
378 cp expect_log_y expect_log_m
379
380 git rev-parse refs/notes/y > pre_merge_y
381 git rev-parse refs/notes/z > pre_merge_z
382
383 test_expect_success 'redo merge of z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
384         git update-ref refs/notes/m refs/notes/y &&
385         git config core.notesRef refs/notes/m &&
386         test_must_fail git notes merge z >output 2>&1 &&
387         # Output should point to where to resolve conflicts
388         test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
389         # Inspect merge conflicts
390         ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
391         test_cmp expect_conflicts output_conflicts &&
392         ( for f in $(cat expect_conflicts); do
393                 test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
394                 exit 1
395         done ) &&
396         # Verify that current notes tree (pre-merge) has not changed (m == y)
397         verify_notes y &&
398         verify_notes m &&
399         test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
400 '
401
402 test_expect_success 'abort notes merge' '
403         git notes merge --abort &&
404         notes_merge_files_gone &&
405         # m has not moved (still == y)
406         test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)" &&
407         # Verify that other notes refs has not changed (w, x, y and z)
408         verify_notes w &&
409         verify_notes x &&
410         verify_notes y &&
411         verify_notes z
412 '
413
414 git rev-parse refs/notes/y > pre_merge_y
415 git rev-parse refs/notes/z > pre_merge_z
416
417 test_expect_success 'redo merge of z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
418         test_must_fail git notes merge z >output 2>&1 &&
419         # Output should point to where to resolve conflicts
420         test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
421         # Inspect merge conflicts
422         ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
423         test_cmp expect_conflicts output_conflicts &&
424         ( for f in $(cat expect_conflicts); do
425                 test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
426                 exit 1
427         done ) &&
428         # Verify that current notes tree (pre-merge) has not changed (m == y)
429         verify_notes y &&
430         verify_notes m &&
431         test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
432 '
433
434 cat <<EOF | sort >expect_notes_m
435 304dfb4325cf243025b9957486eb605a9b51c199 $commit_sha5
436 283b48219aee9a4105f6cab337e789065c82c2b9 $commit_sha2
437 0a59e787e6d688aa6309e56e8c1b89431a0fc1c1 $commit_sha1
438 EOF
439
440 cat >expect_log_m <<EOF
441 $commit_sha5 5th
442 new note on 5th commit
443
444 $commit_sha4 4th
445
446 $commit_sha3 3rd
447
448 $commit_sha2 2nd
449 z notes on 2nd commit
450
451 $commit_sha1 1st
452 y and z notes on 1st commit
453
454 EOF
455
456 test_expect_success 'add + remove notes in finalized merge (z => m)' '
457         # Resolve one conflict
458         cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF &&
459 y and z notes on 1st commit
460 EOF
461         # Remove another conflict
462         rm .git/NOTES_MERGE_WORKTREE/$commit_sha4 &&
463         # Remove a D/F conflict
464         rm .git/NOTES_MERGE_WORKTREE/$commit_sha3 &&
465         # Add a new note
466         echo "new note on 5th commit" > .git/NOTES_MERGE_WORKTREE/$commit_sha5 &&
467         # Finalize merge
468         git notes merge --commit &&
469         notes_merge_files_gone &&
470         # Merge commit has pre-merge y and pre-merge z as parents
471         test "$(git rev-parse refs/notes/m^1)" = "$(cat pre_merge_y)" &&
472         test "$(git rev-parse refs/notes/m^2)" = "$(cat pre_merge_z)" &&
473         # Merge commit mentions the notes refs merged
474         git log -1 --format=%B refs/notes/m > merge_commit_msg &&
475         grep -q refs/notes/m merge_commit_msg &&
476         grep -q refs/notes/z merge_commit_msg &&
477         # Merge commit mentions conflicting notes
478         grep -q "Conflicts" merge_commit_msg &&
479         ( for sha1 in $(cat expect_conflicts); do
480                 grep -q "$sha1" merge_commit_msg ||
481                 exit 1
482         done ) &&
483         # Verify contents of merge result
484         verify_notes m &&
485         # Verify that other notes refs has not changed (w, x, y and z)
486         verify_notes w &&
487         verify_notes x &&
488         verify_notes y &&
489         verify_notes z
490 '
491
492 cp expect_notes_y expect_notes_m
493 cp expect_log_y expect_log_m
494
495 test_expect_success 'redo merge of z into m (== y) with default ("manual") resolver => Conflicting 3-way merge' '
496         git update-ref refs/notes/m refs/notes/y &&
497         test_must_fail git notes merge z >output 2>&1 &&
498         # Output should point to where to resolve conflicts
499         test_i18ngrep "\\.git/NOTES_MERGE_WORKTREE" output &&
500         # Inspect merge conflicts
501         ls .git/NOTES_MERGE_WORKTREE >output_conflicts &&
502         test_cmp expect_conflicts output_conflicts &&
503         ( for f in $(cat expect_conflicts); do
504                 test_cmp "expect_conflict_$f" ".git/NOTES_MERGE_WORKTREE/$f" ||
505                 exit 1
506         done ) &&
507         # Verify that current notes tree (pre-merge) has not changed (m == y)
508         verify_notes y &&
509         verify_notes m &&
510         test "$(git rev-parse refs/notes/m)" = "$(cat pre_merge_y)"
511 '
512
513 cp expect_notes_w expect_notes_m
514 cp expect_log_w expect_log_m
515
516 test_expect_success 'reset notes ref m to somewhere else (w)' '
517         git update-ref refs/notes/m refs/notes/w &&
518         verify_notes m &&
519         test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)"
520 '
521
522 test_expect_success 'fail to finalize conflicting merge if underlying ref has moved in the meantime (m != NOTES_MERGE_PARTIAL^1)' '
523         # Resolve conflicts
524         cat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF &&
525 y and z notes on 1st commit
526 EOF
527         cat >.git/NOTES_MERGE_WORKTREE/$commit_sha4 <<EOF &&
528 y and z notes on 4th commit
529 EOF
530         # Fail to finalize merge
531         test_must_fail git notes merge --commit >output 2>&1 &&
532         # .git/NOTES_MERGE_* must remain
533         test -f .git/NOTES_MERGE_PARTIAL &&
534         test -f .git/NOTES_MERGE_REF &&
535         test -f .git/NOTES_MERGE_WORKTREE/$commit_sha1 &&
536         test -f .git/NOTES_MERGE_WORKTREE/$commit_sha2 &&
537         test -f .git/NOTES_MERGE_WORKTREE/$commit_sha3 &&
538         test -f .git/NOTES_MERGE_WORKTREE/$commit_sha4 &&
539         # Refs are unchanged
540         test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
541         test "$(git rev-parse refs/notes/y)" = "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
542         test "$(git rev-parse refs/notes/m)" != "$(git rev-parse NOTES_MERGE_PARTIAL^1)" &&
543         # Mention refs/notes/m, and its current and expected value in output
544         test_i18ngrep -q "refs/notes/m" output &&
545         test_i18ngrep -q "$(git rev-parse refs/notes/m)" output &&
546         test_i18ngrep -q "$(git rev-parse NOTES_MERGE_PARTIAL^1)" output &&
547         # Verify that other notes refs has not changed (w, x, y and z)
548         verify_notes w &&
549         verify_notes x &&
550         verify_notes y &&
551         verify_notes z
552 '
553
554 test_expect_success 'resolve situation by aborting the notes merge' '
555         git notes merge --abort &&
556         notes_merge_files_gone &&
557         # m has not moved (still == w)
558         test "$(git rev-parse refs/notes/m)" = "$(git rev-parse refs/notes/w)" &&
559         # Verify that other notes refs has not changed (w, x, y and z)
560         verify_notes w &&
561         verify_notes x &&
562         verify_notes y &&
563         verify_notes z
564 '
565
566 cat >expect_notes <<EOF
567 foo
568 bar
569 EOF
570
571 test_expect_success 'switch cwd before committing notes merge' '
572         git notes add -m foo HEAD &&
573         git notes --ref=other add -m bar HEAD &&
574         test_must_fail git notes merge refs/notes/other &&
575         (
576                 cd .git/NOTES_MERGE_WORKTREE &&
577                 echo "foo" > $(git rev-parse HEAD) &&
578                 echo "bar" >> $(git rev-parse HEAD) &&
579                 git notes merge --commit
580         ) &&
581         git notes show HEAD > actual_notes &&
582         test_cmp expect_notes actual_notes
583 '
584
585 test_done