git-apply: try threeway first when "--3way" is used
[git] / t / t3415-rebase-autosquash.sh
1 #!/bin/sh
2
3 test_description='auto squash'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9
10 . "$TEST_DIRECTORY"/lib-rebase.sh
11
12 test_expect_success setup '
13         echo 0 >file0 &&
14         git add . &&
15         test_tick &&
16         git commit -m "initial commit" &&
17         echo 0 >file1 &&
18         echo 2 >file2 &&
19         git add . &&
20         test_tick &&
21         git commit -m "first commit" &&
22         git tag first-commit &&
23         echo 3 >file3 &&
24         git add . &&
25         test_tick &&
26         git commit -m "second commit" &&
27         git tag base
28 '
29
30 test_auto_fixup () {
31         no_squash= &&
32         if test "x$1" = 'x!'
33         then
34                 no_squash=true
35                 shift
36         fi &&
37
38         git reset --hard base &&
39         echo 1 >file1 &&
40         git add -u &&
41         test_tick &&
42         git commit -m "fixup! first" &&
43
44         git tag $1 &&
45         test_tick &&
46         git rebase $2 -i HEAD^^^ &&
47         git log --oneline >actual &&
48         if test -n "$no_squash"
49         then
50                 test_line_count = 4 actual
51         else
52                 test_line_count = 3 actual &&
53                 git diff --exit-code $1 &&
54                 echo 1 >expect &&
55                 git cat-file blob HEAD^:file1 >actual &&
56                 test_cmp expect actual &&
57                 git cat-file commit HEAD^ >commit &&
58                 grep first commit >actual &&
59                 test_line_count = 1 actual
60         fi
61 }
62
63 test_expect_success 'auto fixup (option)' '
64         test_auto_fixup final-fixup-option --autosquash
65 '
66
67 test_expect_success 'auto fixup (config)' '
68         git config rebase.autosquash true &&
69         test_auto_fixup final-fixup-config-true &&
70         test_auto_fixup ! fixup-config-true-no --no-autosquash &&
71         git config rebase.autosquash false &&
72         test_auto_fixup ! final-fixup-config-false
73 '
74
75 test_auto_squash () {
76         no_squash= &&
77         if test "x$1" = 'x!'
78         then
79                 no_squash=true
80                 shift
81         fi &&
82
83         git reset --hard base &&
84         echo 1 >file1 &&
85         git add -u &&
86         test_tick &&
87         git commit -m "squash! first" -m "extra para for first" &&
88         git tag $1 &&
89         test_tick &&
90         git rebase $2 -i HEAD^^^ &&
91         git log --oneline >actual &&
92         if test -n "$no_squash"
93         then
94                 test_line_count = 4 actual
95         else
96                 test_line_count = 3 actual &&
97                 git diff --exit-code $1 &&
98                 echo 1 >expect &&
99                 git cat-file blob HEAD^:file1 >actual &&
100                 test_cmp expect actual &&
101                 git cat-file commit HEAD^ >commit &&
102                 grep first commit >actual &&
103                 test_line_count = 2 actual
104         fi
105 }
106
107 test_expect_success 'auto squash (option)' '
108         test_auto_squash final-squash --autosquash
109 '
110
111 test_expect_success 'auto squash (config)' '
112         git config rebase.autosquash true &&
113         test_auto_squash final-squash-config-true &&
114         test_auto_squash ! squash-config-true-no --no-autosquash &&
115         git config rebase.autosquash false &&
116         test_auto_squash ! final-squash-config-false
117 '
118
119 test_expect_success 'misspelled auto squash' '
120         git reset --hard base &&
121         echo 1 >file1 &&
122         git add -u &&
123         test_tick &&
124         git commit -m "squash! forst" &&
125         git tag final-missquash &&
126         test_tick &&
127         git rebase --autosquash -i HEAD^^^ &&
128         git log --oneline >actual &&
129         test_line_count = 4 actual &&
130         git diff --exit-code final-missquash &&
131         git rev-list final-missquash...HEAD >list &&
132         test_must_be_empty list
133 '
134
135 test_expect_success 'auto squash that matches 2 commits' '
136         git reset --hard base &&
137         echo 4 >file4 &&
138         git add file4 &&
139         test_tick &&
140         git commit -m "first new commit" &&
141         echo 1 >file1 &&
142         git add -u &&
143         test_tick &&
144         git commit -m "squash! first" -m "extra para for first" &&
145         git tag final-multisquash &&
146         test_tick &&
147         git rebase --autosquash -i HEAD~4 &&
148         git log --oneline >actual &&
149         test_line_count = 4 actual &&
150         git diff --exit-code final-multisquash &&
151         echo 1 >expect &&
152         git cat-file blob HEAD^^:file1 >actual &&
153         test_cmp expect actual &&
154         git cat-file commit HEAD^^ >commit &&
155         grep first commit >actual &&
156         test_line_count = 2 actual &&
157         git cat-file commit HEAD >commit &&
158         grep first commit >actual &&
159         test_line_count = 1 actual
160 '
161
162 test_expect_success 'auto squash that matches a commit after the squash' '
163         git reset --hard base &&
164         echo 1 >file1 &&
165         git add -u &&
166         test_tick &&
167         git commit -m "squash! third" &&
168         echo 4 >file4 &&
169         git add file4 &&
170         test_tick &&
171         git commit -m "third commit" &&
172         git tag final-presquash &&
173         test_tick &&
174         git rebase --autosquash -i HEAD~4 &&
175         git log --oneline >actual &&
176         test_line_count = 5 actual &&
177         git diff --exit-code final-presquash &&
178         echo 0 >expect &&
179         git cat-file blob HEAD^^:file1 >actual &&
180         test_cmp expect actual &&
181         echo 1 >expect &&
182         git cat-file blob HEAD^:file1 >actual &&
183         test_cmp expect actual &&
184         git cat-file commit HEAD >commit &&
185         grep third commit >actual &&
186         test_line_count = 1 actual &&
187         git cat-file commit HEAD^ >commit &&
188         grep third commit >actual &&
189         test_line_count = 1 actual
190 '
191 test_expect_success 'auto squash that matches a sha1' '
192         git reset --hard base &&
193         echo 1 >file1 &&
194         git add -u &&
195         test_tick &&
196         oid=$(git rev-parse --short HEAD^) &&
197         git commit -m "squash! $oid" -m "extra para" &&
198         git tag final-shasquash &&
199         test_tick &&
200         git rebase --autosquash -i HEAD^^^ &&
201         git log --oneline >actual &&
202         test_line_count = 3 actual &&
203         git diff --exit-code final-shasquash &&
204         echo 1 >expect &&
205         git cat-file blob HEAD^:file1 >actual &&
206         test_cmp expect actual &&
207         git cat-file commit HEAD^ >commit &&
208         ! grep "squash" commit &&
209         grep "^extra para" commit >actual &&
210         test_line_count = 1 actual
211 '
212
213 test_expect_success 'auto squash that matches longer sha1' '
214         git reset --hard base &&
215         echo 1 >file1 &&
216         git add -u &&
217         test_tick &&
218         oid=$(git rev-parse --short=11 HEAD^) &&
219         git commit -m "squash! $oid" -m "extra para" &&
220         git tag final-longshasquash &&
221         test_tick &&
222         git rebase --autosquash -i HEAD^^^ &&
223         git log --oneline >actual &&
224         test_line_count = 3 actual &&
225         git diff --exit-code final-longshasquash &&
226         echo 1 >expect &&
227         git cat-file blob HEAD^:file1 >actual &&
228         test_cmp expect actual &&
229         git cat-file commit HEAD^ >commit &&
230         ! grep "squash" commit &&
231         grep "^extra para" commit >actual &&
232         test_line_count = 1 actual
233 '
234
235 test_auto_commit_flags () {
236         git reset --hard base &&
237         echo 1 >file1 &&
238         git add -u &&
239         test_tick &&
240         git commit --$1 first-commit -m "extra para for first" &&
241         git tag final-commit-$1 &&
242         test_tick &&
243         git rebase --autosquash -i HEAD^^^ &&
244         git log --oneline >actual &&
245         test_line_count = 3 actual &&
246         git diff --exit-code final-commit-$1 &&
247         echo 1 >expect &&
248         git cat-file blob HEAD^:file1 >actual &&
249         test_cmp expect actual &&
250         git cat-file commit HEAD^ >commit &&
251         grep first commit >actual &&
252         test_line_count = $2 actual
253 }
254
255 test_expect_success 'use commit --fixup' '
256         test_auto_commit_flags fixup 1
257 '
258
259 test_expect_success 'use commit --squash' '
260         test_auto_commit_flags squash 2
261 '
262
263 test_auto_fixup_fixup () {
264         git reset --hard base &&
265         echo 1 >file1 &&
266         git add -u &&
267         test_tick &&
268         git commit -m "$1! first" -m "extra para for first" &&
269         echo 2 >file1 &&
270         git add -u &&
271         test_tick &&
272         git commit -m "$1! $2! first" -m "second extra para for first" &&
273         git tag "final-$1-$2" &&
274         test_tick &&
275         (
276                 set_cat_todo_editor &&
277                 test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
278                 head=$(git rev-parse --short HEAD) &&
279                 parent1=$(git rev-parse --short HEAD^) &&
280                 parent2=$(git rev-parse --short HEAD^^) &&
281                 parent3=$(git rev-parse --short HEAD^^^) &&
282                 cat >expected <<-EOF &&
283                 pick $parent3 first commit
284                 $1 $parent1 $1! first
285                 $1 $head $1! $2! first
286                 pick $parent2 second commit
287                 EOF
288                 test_cmp expected actual
289         ) &&
290         git rebase --autosquash -i HEAD^^^^ &&
291         git log --oneline >actual &&
292         test_line_count = 3 actual
293         git diff --exit-code "final-$1-$2" &&
294         echo 2 >expect &&
295         git cat-file blob HEAD^:file1 >actual &&
296         test_cmp expect actual &&
297         git cat-file commit HEAD^ >commit &&
298         grep first commit >actual &&
299         if test "$1" = "fixup"
300         then
301                 test_line_count = 1 actual
302         elif test "$1" = "squash"
303         then
304                 test_line_count = 3 actual
305         else
306                 false
307         fi
308 }
309
310 test_expect_success 'fixup! fixup!' '
311         test_auto_fixup_fixup fixup fixup
312 '
313
314 test_expect_success 'fixup! squash!' '
315         test_auto_fixup_fixup fixup squash
316 '
317
318 test_expect_success 'squash! squash!' '
319         test_auto_fixup_fixup squash squash
320 '
321
322 test_expect_success 'squash! fixup!' '
323         test_auto_fixup_fixup squash fixup
324 '
325
326 test_expect_success 'autosquash with custom inst format' '
327         git reset --hard base &&
328         git config --add rebase.instructionFormat "[%an @ %ar] %s"  &&
329         echo 2 >file1 &&
330         git add -u &&
331         test_tick &&
332         oid=$(git rev-parse --short HEAD^) &&
333         git commit -m "squash! $oid" -m "extra para for first" &&
334         echo 1 >file1 &&
335         git add -u &&
336         test_tick &&
337         subject=$(git log -n 1 --format=%s HEAD~2) &&
338         git commit -m "squash! $subject" -m "second extra para for first" &&
339         git tag final-squash-instFmt &&
340         test_tick &&
341         git rebase --autosquash -i HEAD~4 &&
342         git log --oneline >actual &&
343         test_line_count = 3 actual &&
344         git diff --exit-code final-squash-instFmt &&
345         echo 1 >expect &&
346         git cat-file blob HEAD^:file1 >actual &&
347         test_cmp expect actual &&
348         git cat-file commit HEAD^ >commit &&
349         ! grep "squash" commit &&
350         grep first commit >actual &&
351         test_line_count = 3 actual
352 '
353
354 test_expect_success 'autosquash with empty custom instructionFormat' '
355         git reset --hard base &&
356         test_commit empty-instructionFormat-test &&
357         (
358                 set_cat_todo_editor &&
359                 test_must_fail git -c rebase.instructionFormat= \
360                         rebase --autosquash  --force-rebase -i HEAD^ >actual &&
361                 git log -1 --format="pick %h %s" >expect &&
362                 test_cmp expect actual
363         )
364 '
365
366 set_backup_editor () {
367         write_script backup-editor.sh <<-\EOF
368         cp "$1" .git/backup-"$(basename "$1")"
369         EOF
370         test_set_editor "$PWD/backup-editor.sh"
371 }
372
373 test_expect_success 'autosquash with multiple empty patches' '
374         test_tick &&
375         git commit --allow-empty -m "empty" &&
376         test_tick &&
377         git commit --allow-empty -m "empty2" &&
378         test_tick &&
379         >fixup &&
380         git add fixup &&
381         git commit --fixup HEAD^^ &&
382         (
383                 set_backup_editor &&
384                 GIT_USE_REBASE_HELPER=false \
385                 git rebase -i --force-rebase --autosquash HEAD~4 &&
386                 grep empty2 .git/backup-git-rebase-todo
387         )
388 '
389
390 test_expect_success 'extra spaces after fixup!' '
391         base=$(git rev-parse HEAD) &&
392         test_commit to-fixup &&
393         git commit --allow-empty -m "fixup!  to-fixup" &&
394         git rebase -i --autosquash --keep-empty HEAD~2 &&
395         parent=$(git rev-parse HEAD^) &&
396         test $base = $parent
397 '
398
399 test_expect_success 'wrapped original subject' '
400         if test -d .git/rebase-merge; then git rebase --abort; fi &&
401         base=$(git rev-parse HEAD) &&
402         echo "wrapped subject" >wrapped &&
403         git add wrapped &&
404         test_tick &&
405         git commit --allow-empty -m "$(printf "To\nfixup")" &&
406         test_tick &&
407         git commit --allow-empty -m "fixup! To fixup" &&
408         git rebase -i --autosquash --keep-empty HEAD~2 &&
409         parent=$(git rev-parse HEAD^) &&
410         test $base = $parent
411 '
412
413 test_expect_success 'abort last squash' '
414         test_when_finished "test_might_fail git rebase --abort" &&
415         test_when_finished "git checkout main" &&
416
417         git checkout -b some-squashes &&
418         git commit --allow-empty -m first &&
419         git commit --allow-empty --squash HEAD &&
420         git commit --allow-empty -m second &&
421         git commit --allow-empty --squash HEAD &&
422
423         test_must_fail git -c core.editor="grep -q ^pick" \
424                 rebase -ki --autosquash HEAD~4 &&
425         : do not finish the squash, but resolve it manually &&
426         git commit --allow-empty --amend -m edited-first &&
427         git rebase --skip &&
428         git show >actual &&
429         ! grep first actual
430 '
431
432 test_expect_success 'fixup a fixup' '
433         echo 0to-fixup >file0 &&
434         test_tick &&
435         git commit -m "to-fixup" file0 &&
436         test_tick &&
437         git commit --squash HEAD -m X --allow-empty &&
438         test_tick &&
439         git commit --squash HEAD^ -m Y --allow-empty &&
440         test_tick &&
441         git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty &&
442         test_tick &&
443         git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty &&
444         git rebase -ki --autosquash HEAD~5 &&
445         test XZWY = $(git show | tr -cd W-Z)
446 '
447
448 test_expect_success 'fixup does not clean up commit message' '
449         oneline="#818" &&
450         git commit --allow-empty -m "$oneline" &&
451         git commit --fixup HEAD --allow-empty &&
452         git -c commit.cleanup=strip rebase -ki --autosquash HEAD~2 &&
453         test "$oneline" = "$(git show -s --format=%s)"
454 '
455
456 test_done