]> git.ipfire.org Git - thirdparty/git.git/blob - t/t3415-rebase-autosquash.sh
Sync with 2.37.6
[thirdparty/git.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_expect_success 'auto squash of fixup commit that matches branch name which points back to fixup commit' '
236 git reset --hard base &&
237 git commit --allow-empty -m "fixup! self-cycle" &&
238 git branch self-cycle &&
239 GIT_SEQUENCE_EDITOR="cat >tmp" git rebase --autosquash -i HEAD^^ &&
240 sed -ne "/^[^#]/{s/[0-9a-f]\{7,\}/HASH/g;p;}" tmp >actual &&
241 cat <<-EOF >expect &&
242 pick HASH second commit
243 pick HASH fixup! self-cycle # empty
244 EOF
245 test_cmp expect actual
246 '
247
248 test_auto_commit_flags () {
249 git reset --hard base &&
250 echo 1 >file1 &&
251 git add -u &&
252 test_tick &&
253 git commit --$1 first-commit -m "extra para for first" &&
254 git tag final-commit-$1 &&
255 test_tick &&
256 git rebase --autosquash -i HEAD^^^ &&
257 git log --oneline >actual &&
258 test_line_count = 3 actual &&
259 git diff --exit-code final-commit-$1 &&
260 echo 1 >expect &&
261 git cat-file blob HEAD^:file1 >actual &&
262 test_cmp expect actual &&
263 git cat-file commit HEAD^ >commit &&
264 grep first commit >actual &&
265 test_line_count = $2 actual
266 }
267
268 test_expect_success 'use commit --fixup' '
269 test_auto_commit_flags fixup 1
270 '
271
272 test_expect_success 'use commit --squash' '
273 test_auto_commit_flags squash 2
274 '
275
276 test_auto_fixup_fixup () {
277 git reset --hard base &&
278 echo 1 >file1 &&
279 git add -u &&
280 test_tick &&
281 git commit -m "$1! first" -m "extra para for first" &&
282 echo 2 >file1 &&
283 git add -u &&
284 test_tick &&
285 git commit -m "$1! $2! first" -m "second extra para for first" &&
286 git tag "final-$1-$2" &&
287 test_tick &&
288 (
289 set_cat_todo_editor &&
290 test_must_fail git rebase --autosquash -i HEAD^^^^ >actual &&
291 head=$(git rev-parse --short HEAD) &&
292 parent1=$(git rev-parse --short HEAD^) &&
293 parent2=$(git rev-parse --short HEAD^^) &&
294 parent3=$(git rev-parse --short HEAD^^^) &&
295 cat >expected <<-EOF &&
296 pick $parent3 first commit
297 $1 $parent1 $1! first
298 $1 $head $1! $2! first
299 pick $parent2 second commit
300 EOF
301 test_cmp expected actual
302 ) &&
303 git rebase --autosquash -i HEAD^^^^ &&
304 git log --oneline >actual &&
305 test_line_count = 3 actual
306 git diff --exit-code "final-$1-$2" &&
307 echo 2 >expect &&
308 git cat-file blob HEAD^:file1 >actual &&
309 test_cmp expect actual &&
310 git cat-file commit HEAD^ >commit &&
311 grep first commit >actual &&
312 if test "$1" = "fixup"
313 then
314 test_line_count = 1 actual
315 elif test "$1" = "squash"
316 then
317 test_line_count = 3 actual
318 else
319 false
320 fi
321 }
322
323 test_expect_success 'fixup! fixup!' '
324 test_auto_fixup_fixup fixup fixup
325 '
326
327 test_expect_success 'fixup! squash!' '
328 test_auto_fixup_fixup fixup squash
329 '
330
331 test_expect_success 'squash! squash!' '
332 test_auto_fixup_fixup squash squash
333 '
334
335 test_expect_success 'squash! fixup!' '
336 test_auto_fixup_fixup squash fixup
337 '
338
339 test_expect_success 'autosquash with custom inst format' '
340 git reset --hard base &&
341 git config --add rebase.instructionFormat "[%an @ %ar] %s" &&
342 echo 2 >file1 &&
343 git add -u &&
344 test_tick &&
345 oid=$(git rev-parse --short HEAD^) &&
346 git commit -m "squash! $oid" -m "extra para for first" &&
347 echo 1 >file1 &&
348 git add -u &&
349 test_tick &&
350 subject=$(git log -n 1 --format=%s HEAD~2) &&
351 git commit -m "squash! $subject" -m "second extra para for first" &&
352 git tag final-squash-instFmt &&
353 test_tick &&
354 git rebase --autosquash -i HEAD~4 &&
355 git log --oneline >actual &&
356 test_line_count = 3 actual &&
357 git diff --exit-code final-squash-instFmt &&
358 echo 1 >expect &&
359 git cat-file blob HEAD^:file1 >actual &&
360 test_cmp expect actual &&
361 git cat-file commit HEAD^ >commit &&
362 ! grep "squash" commit &&
363 grep first commit >actual &&
364 test_line_count = 3 actual
365 '
366
367 test_expect_success 'autosquash with empty custom instructionFormat' '
368 git reset --hard base &&
369 test_commit empty-instructionFormat-test &&
370 (
371 set_cat_todo_editor &&
372 test_must_fail git -c rebase.instructionFormat= \
373 rebase --autosquash --force-rebase -i HEAD^ >actual &&
374 git log -1 --format="pick %h %s" >expect &&
375 test_cmp expect actual
376 )
377 '
378
379 set_backup_editor () {
380 write_script backup-editor.sh <<-\EOF
381 cp "$1" .git/backup-"$(basename "$1")"
382 EOF
383 test_set_editor "$PWD/backup-editor.sh"
384 }
385
386 test_expect_success 'autosquash with multiple empty patches' '
387 test_tick &&
388 git commit --allow-empty -m "empty" &&
389 test_tick &&
390 git commit --allow-empty -m "empty2" &&
391 test_tick &&
392 >fixup &&
393 git add fixup &&
394 git commit --fixup HEAD^^ &&
395 (
396 set_backup_editor &&
397 GIT_USE_REBASE_HELPER=false \
398 git rebase -i --force-rebase --autosquash HEAD~4 &&
399 grep empty2 .git/backup-git-rebase-todo
400 )
401 '
402
403 test_expect_success 'extra spaces after fixup!' '
404 base=$(git rev-parse HEAD) &&
405 test_commit to-fixup &&
406 git commit --allow-empty -m "fixup! to-fixup" &&
407 git rebase -i --autosquash --keep-empty HEAD~2 &&
408 parent=$(git rev-parse HEAD^) &&
409 test $base = $parent
410 '
411
412 test_expect_success 'wrapped original subject' '
413 if test -d .git/rebase-merge; then git rebase --abort; fi &&
414 base=$(git rev-parse HEAD) &&
415 echo "wrapped subject" >wrapped &&
416 git add wrapped &&
417 test_tick &&
418 git commit --allow-empty -m "$(printf "To\nfixup")" &&
419 test_tick &&
420 git commit --allow-empty -m "fixup! To fixup" &&
421 git rebase -i --autosquash --keep-empty HEAD~2 &&
422 parent=$(git rev-parse HEAD^) &&
423 test $base = $parent
424 '
425
426 test_expect_success 'abort last squash' '
427 test_when_finished "test_might_fail git rebase --abort" &&
428 test_when_finished "git checkout main" &&
429
430 git checkout -b some-squashes &&
431 git commit --allow-empty -m first &&
432 git commit --allow-empty --squash HEAD &&
433 git commit --allow-empty -m second &&
434 git commit --allow-empty --squash HEAD &&
435
436 test_must_fail git -c core.editor="grep -q ^pick" \
437 rebase -ki --autosquash HEAD~4 &&
438 : do not finish the squash, but resolve it manually &&
439 git commit --allow-empty --amend -m edited-first &&
440 git rebase --skip &&
441 git show >actual &&
442 ! grep first actual
443 '
444
445 test_expect_success 'fixup a fixup' '
446 echo 0to-fixup >file0 &&
447 test_tick &&
448 git commit -m "to-fixup" file0 &&
449 test_tick &&
450 git commit --squash HEAD -m X --allow-empty &&
451 test_tick &&
452 git commit --squash HEAD^ -m Y --allow-empty &&
453 test_tick &&
454 git commit -m "squash! $(git rev-parse HEAD^)" -m Z --allow-empty &&
455 test_tick &&
456 git commit -m "squash! $(git rev-parse HEAD^^)" -m W --allow-empty &&
457 git rebase -ki --autosquash HEAD~5 &&
458 test XZWY = $(git show | tr -cd W-Z)
459 '
460
461 test_expect_success 'fixup does not clean up commit message' '
462 oneline="#818" &&
463 git commit --allow-empty -m "$oneline" &&
464 git commit --fixup HEAD --allow-empty &&
465 git -c commit.cleanup=strip rebase -ki --autosquash HEAD~2 &&
466 test "$oneline" = "$(git show -s --format=%s)"
467 '
468
469 test_done