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