Merge branch 'ds/cache-tree-basics'
[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" &&
88
89         git tag $1 &&
90         test_tick &&
91         git rebase $2 -i HEAD^^^ &&
92         git log --oneline >actual &&
93         if test -n "$no_squash"
94         then
95                 test_line_count = 4 actual
96         else
97                 test_line_count = 3 actual &&
98                 git diff --exit-code $1 &&
99                 echo 1 >expect &&
100                 git cat-file blob HEAD^:file1 >actual &&
101                 test_cmp expect actual &&
102                 git cat-file commit HEAD^ >commit &&
103                 grep first commit >actual &&
104                 test_line_count = 2 actual
105         fi
106 }
107
108 test_expect_success 'auto squash (option)' '
109         test_auto_squash final-squash --autosquash
110 '
111
112 test_expect_success 'auto squash (config)' '
113         git config rebase.autosquash true &&
114         test_auto_squash final-squash-config-true &&
115         test_auto_squash ! squash-config-true-no --no-autosquash &&
116         git config rebase.autosquash false &&
117         test_auto_squash ! final-squash-config-false
118 '
119
120 test_expect_success 'misspelled auto squash' '
121         git reset --hard base &&
122         echo 1 >file1 &&
123         git add -u &&
124         test_tick &&
125         git commit -m "squash! forst" &&
126         git tag final-missquash &&
127         test_tick &&
128         git rebase --autosquash -i HEAD^^^ &&
129         git log --oneline >actual &&
130         test_line_count = 4 actual &&
131         git diff --exit-code final-missquash &&
132         git rev-list final-missquash...HEAD >list &&
133         test_must_be_empty list
134 '
135
136 test_expect_success 'auto squash that matches 2 commits' '
137         git reset --hard base &&
138         echo 4 >file4 &&
139         git add file4 &&
140         test_tick &&
141         git commit -m "first new commit" &&
142         echo 1 >file1 &&
143         git add -u &&
144         test_tick &&
145         git commit -m "squash! first" &&
146         git tag final-multisquash &&
147         test_tick &&
148         git rebase --autosquash -i HEAD~4 &&
149         git log --oneline >actual &&
150         test_line_count = 4 actual &&
151         git diff --exit-code final-multisquash &&
152         echo 1 >expect &&
153         git cat-file blob HEAD^^:file1 >actual &&
154         test_cmp expect actual &&
155         git cat-file commit HEAD^^ >commit &&
156         grep first commit >actual &&
157         test_line_count = 2 actual &&
158         git cat-file commit HEAD >commit &&
159         grep first commit >actual &&
160         test_line_count = 1 actual
161 '
162
163 test_expect_success 'auto squash that matches a commit after the squash' '
164         git reset --hard base &&
165         echo 1 >file1 &&
166         git add -u &&
167         test_tick &&
168         git commit -m "squash! third" &&
169         echo 4 >file4 &&
170         git add file4 &&
171         test_tick &&
172         git commit -m "third commit" &&
173         git tag final-presquash &&
174         test_tick &&
175         git rebase --autosquash -i HEAD~4 &&
176         git log --oneline >actual &&
177         test_line_count = 5 actual &&
178         git diff --exit-code final-presquash &&
179         echo 0 >expect &&
180         git cat-file blob HEAD^^:file1 >actual &&
181         test_cmp expect actual &&
182         echo 1 >expect &&
183         git cat-file blob HEAD^:file1 >actual &&
184         test_cmp expect actual &&
185         git cat-file commit HEAD >commit &&
186         grep third commit >actual &&
187         test_line_count = 1 actual &&
188         git cat-file commit HEAD^ >commit &&
189         grep third commit >actual &&
190         test_line_count = 1 actual
191 '
192 test_expect_success 'auto squash that matches a sha1' '
193         git reset --hard base &&
194         echo 1 >file1 &&
195         git add -u &&
196         test_tick &&
197         oid=$(git rev-parse --short HEAD^) &&
198         git commit -m "squash! $oid" &&
199         git tag final-shasquash &&
200         test_tick &&
201         git rebase --autosquash -i HEAD^^^ &&
202         git log --oneline >actual &&
203         test_line_count = 3 actual &&
204         git diff --exit-code final-shasquash &&
205         echo 1 >expect &&
206         git cat-file blob HEAD^:file1 >actual &&
207         test_cmp expect actual &&
208         git cat-file commit HEAD^ >commit &&
209         grep squash 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" &&
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 >actual &&
231         test_line_count = 1 actual
232 '
233
234 test_auto_commit_flags () {
235         git reset --hard base &&
236         echo 1 >file1 &&
237         git add -u &&
238         test_tick &&
239         git commit --$1 first-commit &&
240         git tag final-commit-$1 &&
241         test_tick &&
242         git rebase --autosquash -i HEAD^^^ &&
243         git log --oneline >actual &&
244         test_line_count = 3 actual &&
245         git diff --exit-code final-commit-$1 &&
246         echo 1 >expect &&
247         git cat-file blob HEAD^:file1 >actual &&
248         test_cmp expect actual &&
249         git cat-file commit HEAD^ >commit &&
250         grep first commit >actual &&
251         test_line_count = $2 actual
252 }
253
254 test_expect_success 'use commit --fixup' '
255         test_auto_commit_flags fixup 1
256 '
257
258 test_expect_success 'use commit --squash' '
259         test_auto_commit_flags squash 2
260 '
261
262 test_auto_fixup_fixup () {
263         git reset --hard base &&
264         echo 1 >file1 &&
265         git add -u &&
266         test_tick &&
267         git commit -m "$1! first" &&
268         echo 2 >file1 &&
269         git add -u &&
270         test_tick &&
271         git commit -m "$1! $2! first" &&
272         git tag "final-$1-$2" &&
273         test_tick &&
274         (
275                 set_cat_todo_editor &&
276                 test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
277                 head=$(git rev-parse --short HEAD) &&
278                 parent1=$(git rev-parse --short HEAD^) &&
279                 parent2=$(git rev-parse --short HEAD^^) &&
280                 parent3=$(git rev-parse --short HEAD^^^) &&
281                 cat >expected <<-EOF &&
282                 pick $parent3 first commit
283                 $1 $parent1 $1! first
284                 $1 $head $1! $2! first
285                 pick $parent2 second commit
286                 EOF
287                 test_cmp expected actual
288         ) &&
289         git rebase --autosquash -i HEAD^^^^ &&
290         git log --oneline >actual &&
291         test_line_count = 3 actual
292         git diff --exit-code "final-$1-$2" &&
293         echo 2 >expect &&
294         git cat-file blob HEAD^:file1 >actual &&
295         test_cmp expect actual &&
296         git cat-file commit HEAD^ >commit &&
297         grep first commit >actual &&
298         if test "$1" = "fixup"
299         then
300                 test_line_count = 1 actual
301         elif test "$1" = "squash"
302         then
303                 test_line_count = 3 actual
304         else
305                 false
306         fi
307 }
308
309 test_expect_success C_LOCALE_OUTPUT 'fixup! fixup!' '
310         test_auto_fixup_fixup fixup fixup
311 '
312
313 test_expect_success C_LOCALE_OUTPUT 'fixup! squash!' '
314         test_auto_fixup_fixup fixup squash
315 '
316
317 test_expect_success C_LOCALE_OUTPUT 'squash! squash!' '
318         test_auto_fixup_fixup squash squash
319 '
320
321 test_expect_success C_LOCALE_OUTPUT 'squash! fixup!' '
322         test_auto_fixup_fixup squash fixup
323 '
324
325 test_expect_success C_LOCALE_OUTPUT 'autosquash with custom inst format' '
326         git reset --hard base &&
327         git config --add rebase.instructionFormat "[%an @ %ar] %s"  &&
328         echo 2 >file1 &&
329         git add -u &&
330         test_tick &&
331         oid=$(git rev-parse --short HEAD^) &&
332         git commit -m "squash! $oid" &&
333         echo 1 >file1 &&
334         git add -u &&
335         test_tick &&
336         subject=$(git log -n 1 --format=%s HEAD~2) &&
337         git commit -m "squash! $subject" &&
338         git tag final-squash-instFmt &&
339         test_tick &&
340         git rebase --autosquash -i HEAD~4 &&
341         git log --oneline >actual &&
342         test_line_count = 3 actual &&
343         git diff --exit-code final-squash-instFmt &&
344         echo 1 >expect &&
345         git cat-file blob HEAD^:file1 >actual &&
346         test_cmp expect actual &&
347         git cat-file commit HEAD^ >commit &&
348         grep squash commit >actual &&
349         test_line_count = 2 actual
350 '
351
352 test_expect_success 'autosquash with empty custom instructionFormat' '
353         git reset --hard base &&
354         test_commit empty-instructionFormat-test &&
355         (
356                 set_cat_todo_editor &&
357                 test_must_fail git -c rebase.instructionFormat= \
358                         rebase --autosquash  --force-rebase -i HEAD^ >actual &&
359                 git log -1 --format="pick %h %s" >expect &&
360                 test_cmp expect actual
361         )
362 '
363
364 set_backup_editor () {
365         write_script backup-editor.sh <<-\EOF
366         cp "$1" .git/backup-"$(basename "$1")"
367         EOF
368         test_set_editor "$PWD/backup-editor.sh"
369 }
370
371 test_expect_success 'autosquash with multiple empty patches' '
372         test_tick &&
373         git commit --allow-empty -m "empty" &&
374         test_tick &&
375         git commit --allow-empty -m "empty2" &&
376         test_tick &&
377         >fixup &&
378         git add fixup &&
379         git commit --fixup HEAD^^ &&
380         (
381                 set_backup_editor &&
382                 GIT_USE_REBASE_HELPER=false \
383                 git rebase -i --force-rebase --autosquash HEAD~4 &&
384                 grep empty2 .git/backup-git-rebase-todo
385         )
386 '
387
388 test_expect_success 'extra spaces after fixup!' '
389         base=$(git rev-parse HEAD) &&
390         test_commit to-fixup &&
391         git commit --allow-empty -m "fixup!  to-fixup" &&
392         git rebase -i --autosquash --keep-empty HEAD~2 &&
393         parent=$(git rev-parse HEAD^) &&
394         test $base = $parent
395 '
396
397 test_expect_success 'wrapped original subject' '
398         if test -d .git/rebase-merge; then git rebase --abort; fi &&
399         base=$(git rev-parse HEAD) &&
400         echo "wrapped subject" >wrapped &&
401         git add wrapped &&
402         test_tick &&
403         git commit --allow-empty -m "$(printf "To\nfixup")" &&
404         test_tick &&
405         git commit --allow-empty -m "fixup! To fixup" &&
406         git rebase -i --autosquash --keep-empty HEAD~2 &&
407         parent=$(git rev-parse HEAD^) &&
408         test $base = $parent
409 '
410
411 test_expect_success 'abort last squash' '
412         test_when_finished "test_might_fail git rebase --abort" &&
413         test_when_finished "git checkout main" &&
414
415         git checkout -b some-squashes &&
416         git commit --allow-empty -m first &&
417         git commit --allow-empty --squash HEAD &&
418         git commit --allow-empty -m second &&
419         git commit --allow-empty --squash HEAD &&
420
421         test_must_fail git -c core.editor="grep -q ^pick" \
422                 rebase -ki --autosquash HEAD~4 &&
423         : do not finish the squash, but resolve it manually &&
424         git commit --allow-empty --amend -m edited-first &&
425         git rebase --skip &&
426         git show >actual &&
427         ! grep first actual
428 '
429
430 test_expect_success 'fixup a fixup' '
431         echo 0to-fixup >file0 &&
432         test_tick &&
433         git commit -m "to-fixup" file0 &&
434         test_tick &&
435         git commit --squash HEAD -m X --allow-empty &&
436         test_tick &&
437         git commit --squash HEAD^ -m Y --allow-empty &&
438         test_tick &&
439         git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty &&
440         test_tick &&
441         git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty &&
442         git rebase -ki --autosquash HEAD~5 &&
443         test XZWY = $(git show | tr -cd W-Z)
444 '
445
446 test_done