Merge branch 'en/merge-ort-perf'
[git] / t / t7502-commit-porcelain.sh
1 #!/bin/sh
2
3 test_description='git commit porcelain-ish'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9
10 commit_msg_is () {
11         expect=commit_msg_is.expect
12         actual=commit_msg_is.actual
13
14         printf "%s" "$(git log --pretty=format:%s%b -1)" >$actual &&
15         printf "%s" "$1" >$expect &&
16         test_i18ncmp $expect $actual
17 }
18
19 # Arguments: [<prefix] [<commit message>] [<commit options>]
20 check_summary_oneline() {
21         test_tick &&
22         git commit ${3+"$3"} -m "$2" >raw &&
23         head -n 1 raw >act &&
24
25         # branch name
26         SUMMARY_PREFIX="$(git name-rev --name-only HEAD)" &&
27
28         # append the "special" prefix, like "root-commit", "detached HEAD"
29         if test -n "$1"
30         then
31                 SUMMARY_PREFIX="$SUMMARY_PREFIX ($1)"
32         fi
33
34         # abbrev SHA-1
35         SUMMARY_POSTFIX="$(git log -1 --pretty='format:%h')"
36         echo "[$SUMMARY_PREFIX $SUMMARY_POSTFIX] $2" >exp &&
37
38         test_i18ncmp exp act
39 }
40
41 test_expect_success 'output summary format' '
42
43         echo new >file1 &&
44         git add file1 &&
45         check_summary_oneline "root-commit" "initial" &&
46
47         echo change >>file1 &&
48         git add file1
49 '
50
51 test_expect_success 'output summary format: root-commit' '
52         check_summary_oneline "" "a change"
53 '
54
55 test_expect_success 'output summary format for commit with an empty diff' '
56
57         check_summary_oneline "" "empty" "--allow-empty"
58 '
59
60 test_expect_success 'output summary format for merges' '
61
62         git checkout -b recursive-base &&
63         test_commit base file1 &&
64
65         git checkout -b recursive-a recursive-base &&
66         test_commit commit-a file1 &&
67
68         git checkout -b recursive-b recursive-base &&
69         test_commit commit-b file1 &&
70
71         # conflict
72         git checkout recursive-a &&
73         test_must_fail git merge recursive-b &&
74         # resolve the conflict
75         echo commit-a >file1 &&
76         git add file1 &&
77         check_summary_oneline "" "Merge"
78 '
79
80 output_tests_cleanup() {
81         # this is needed for "do not fire editor in the presence of conflicts"
82         git checkout main &&
83
84         # this is needed for the "partial removal" test to pass
85         git rm file1 &&
86         git commit -m "cleanup"
87 }
88
89 test_expect_success 'the basics' '
90
91         output_tests_cleanup &&
92
93         echo doing partial >"commit is" &&
94         mkdir not &&
95         echo very much encouraged but we should >not/forbid &&
96         git add "commit is" not &&
97         echo update added "commit is" file >"commit is" &&
98         echo also update another >not/forbid &&
99         test_tick &&
100         git commit -a -m "initial with -a" &&
101
102         git cat-file blob HEAD:"commit is" >current.1 &&
103         git cat-file blob HEAD:not/forbid >current.2 &&
104
105         cmp current.1 "commit is" &&
106         cmp current.2 not/forbid
107
108 '
109
110 test_expect_success 'partial' '
111
112         echo another >"commit is" &&
113         echo another >not/forbid &&
114         test_tick &&
115         git commit -m "partial commit to handle a file" "commit is" &&
116
117         changed=$(git diff-tree --name-only HEAD^ HEAD) &&
118         test "$changed" = "commit is"
119
120 '
121
122 test_expect_success 'partial modification in a subdirectory' '
123
124         test_tick &&
125         git commit -m "partial commit to subdirectory" not &&
126
127         changed=$(git diff-tree -r --name-only HEAD^ HEAD) &&
128         test "$changed" = "not/forbid"
129
130 '
131
132 test_expect_success 'partial removal' '
133
134         git rm not/forbid &&
135         git commit -m "partial commit to remove not/forbid" not &&
136
137         changed=$(git diff-tree -r --name-only HEAD^ HEAD) &&
138         test "$changed" = "not/forbid" &&
139         remain=$(git ls-tree -r --name-only HEAD) &&
140         test "$remain" = "commit is"
141
142 '
143
144 test_expect_success 'sign off' '
145
146         >positive &&
147         git add positive &&
148         git commit -s -m "thank you" &&
149         git cat-file commit HEAD >commit.msg &&
150         sed -ne "s/Signed-off-by: //p" commit.msg >actual &&
151         git var GIT_COMMITTER_IDENT >ident &&
152         sed -e "s/>.*/>/" ident >expected &&
153         test_cmp expected actual
154
155 '
156
157 test_expect_success 'multiple -m' '
158
159         >negative &&
160         git add negative &&
161         git commit -m "one" -m "two" -m "three" &&
162         actual=$(git cat-file commit HEAD >tmp && sed -e "1,/^\$/d" tmp && rm tmp) &&
163         expected=$(test_write_lines "one" "" "two" "" "three") &&
164         test "z$actual" = "z$expected"
165
166 '
167
168 test_expect_success 'verbose' '
169
170         echo minus >negative &&
171         git add negative &&
172         git status -v >raw &&
173         sed -ne "/^diff --git /p" raw >actual &&
174         echo "diff --git a/negative b/negative" >expect &&
175         test_cmp expect actual
176
177 '
178
179 test_expect_success 'verbose respects diff config' '
180
181         test_config diff.noprefix true &&
182         git status -v >actual &&
183         grep "diff --git negative negative" actual
184 '
185
186 mesg_with_comment_and_newlines='
187 # text
188
189 '
190
191 test_expect_success 'prepare file with comment line and trailing newlines'  '
192         printf "%s" "$mesg_with_comment_and_newlines" >expect
193 '
194
195 test_expect_success 'cleanup commit messages (verbatim option,-t)' '
196
197         echo >>negative &&
198         git commit --cleanup=verbatim --no-status -t expect -a &&
199         git cat-file -p HEAD >raw &&
200         sed -e "1,/^\$/d" raw >actual &&
201         test_cmp expect actual
202
203 '
204
205 test_expect_success 'cleanup commit messages (verbatim option,-F)' '
206
207         echo >>negative &&
208         git commit --cleanup=verbatim -F expect -a &&
209         git cat-file -p HEAD >raw &&
210         sed -e "1,/^\$/d" raw >actual &&
211         test_cmp expect actual
212
213 '
214
215 test_expect_success 'cleanup commit messages (verbatim option,-m)' '
216
217         echo >>negative &&
218         git commit --cleanup=verbatim -m "$mesg_with_comment_and_newlines" -a &&
219         git cat-file -p HEAD >raw &&
220         sed -e "1,/^\$/d" raw >actual &&
221         test_cmp expect actual
222
223 '
224
225 test_expect_success 'cleanup commit messages (whitespace option,-F)' '
226
227         echo >>negative &&
228         test_write_lines "" "# text" "" >text &&
229         echo "# text" >expect &&
230         git commit --cleanup=whitespace -F text -a &&
231         git cat-file -p HEAD >raw &&
232         sed -e "1,/^\$/d" raw >actual &&
233         test_cmp expect actual
234
235 '
236
237 test_expect_success 'cleanup commit messages (scissors option,-F,-e)' '
238
239         echo >>negative &&
240         cat >text <<-\EOF &&
241
242         # to be kept
243
244           # ------------------------ >8 ------------------------
245         # to be kept, too
246         # ------------------------ >8 ------------------------
247         to be removed
248         # ------------------------ >8 ------------------------
249         to be removed, too
250         EOF
251
252         cat >expect <<-\EOF &&
253         # to be kept
254
255           # ------------------------ >8 ------------------------
256         # to be kept, too
257         EOF
258         git commit --cleanup=scissors -e -F text -a &&
259         git cat-file -p HEAD >raw &&
260         sed -e "1,/^\$/d" raw >actual &&
261         test_cmp expect actual
262 '
263
264 test_expect_success 'cleanup commit messages (scissors option,-F,-e, scissors on first line)' '
265
266         echo >>negative &&
267         cat >text <<-\EOF &&
268         # ------------------------ >8 ------------------------
269         to be removed
270         EOF
271         git commit --cleanup=scissors -e -F text -a --allow-empty-message &&
272         git cat-file -p HEAD >raw &&
273         sed -e "1,/^\$/d" raw >actual &&
274         test_must_be_empty actual
275 '
276
277 test_expect_success 'cleanup commit messages (strip option,-F)' '
278
279         echo >>negative &&
280         test_write_lines "" "# text" "sample" "" >text &&
281         echo sample >expect &&
282         git commit --cleanup=strip -F text -a &&
283         git cat-file -p HEAD >raw &&
284         sed -e "1,/^\$/d" raw >actual &&
285         test_cmp expect actual
286
287 '
288
289 test_expect_success 'cleanup commit messages (strip option,-F,-e)' '
290
291         echo >>negative &&
292         test_write_lines "" "sample" "" >text &&
293         git commit -e -F text -a &&
294         head -n 4 .git/COMMIT_EDITMSG >actual
295 '
296
297 echo "sample
298
299 # Please enter the commit message for your changes. Lines starting
300 # with '#' will be ignored, and an empty message aborts the commit." >expect
301
302 test_expect_success 'cleanup commit messages (strip option,-F,-e): output' '
303         test_i18ncmp expect actual
304 '
305
306 test_expect_success 'cleanup commit message (fail on invalid cleanup mode option)' '
307         test_must_fail git commit --cleanup=non-existent
308 '
309
310 test_expect_success 'cleanup commit message (fail on invalid cleanup mode configuration)' '
311         test_must_fail git -c commit.cleanup=non-existent commit
312 '
313
314 test_expect_success 'cleanup commit message (no config and no option uses default)' '
315         echo content >>file &&
316         git add file &&
317         (
318           test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
319           git commit --no-status
320         ) &&
321         commit_msg_is "commit message"
322 '
323
324 test_expect_success 'cleanup commit message (option overrides default)' '
325         echo content >>file &&
326         git add file &&
327         (
328           test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
329           git commit --cleanup=whitespace --no-status
330         ) &&
331         commit_msg_is "commit message # comment"
332 '
333
334 test_expect_success 'cleanup commit message (config overrides default)' '
335         echo content >>file &&
336         git add file &&
337         (
338           test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
339           git -c commit.cleanup=whitespace commit --no-status
340         ) &&
341         commit_msg_is "commit message # comment"
342 '
343
344 test_expect_success 'cleanup commit message (option overrides config)' '
345         echo content >>file &&
346         git add file &&
347         (
348           test_set_editor "$TEST_DIRECTORY"/t7500/add-content-and-comment &&
349           git -c commit.cleanup=whitespace commit --cleanup=default
350         ) &&
351         commit_msg_is "commit message"
352 '
353
354 test_expect_success 'cleanup commit message (default, -m)' '
355         echo content >>file &&
356         git add file &&
357         git commit -m "message #comment " &&
358         commit_msg_is "message #comment"
359 '
360
361 test_expect_success 'cleanup commit message (whitespace option, -m)' '
362         echo content >>file &&
363         git add file &&
364         git commit --cleanup=whitespace --no-status -m "message #comment " &&
365         commit_msg_is "message #comment"
366 '
367
368 test_expect_success 'cleanup commit message (whitespace config, -m)' '
369         echo content >>file &&
370         git add file &&
371         git -c commit.cleanup=whitespace commit --no-status -m "message #comment " &&
372         commit_msg_is "message #comment"
373 '
374
375 test_expect_success 'message shows author when it is not equal to committer' '
376         echo >>negative &&
377         git commit -e -m "sample" -a &&
378         test_i18ngrep \
379           "^# Author: *A U Thor <author@example.com>\$" \
380           .git/COMMIT_EDITMSG
381 '
382
383 test_expect_success 'message shows date when it is explicitly set' '
384         git commit --allow-empty -e -m foo --date="2010-01-02T03:04:05" &&
385         test_i18ngrep \
386           "^# Date: *Sat Jan 2 03:04:05 2010 +0000" \
387           .git/COMMIT_EDITMSG
388 '
389
390 test_expect_success AUTOIDENT 'message shows committer when it is automatic' '
391
392         echo >>negative &&
393         (
394                 sane_unset GIT_COMMITTER_EMAIL &&
395                 sane_unset GIT_COMMITTER_NAME &&
396                 git commit -e -m "sample" -a
397         ) &&
398         # the ident is calculated from the system, so we cannot
399         # check the actual value, only that it is there
400         test_i18ngrep "^# Committer: " .git/COMMIT_EDITMSG
401 '
402
403 write_script .git/FAKE_EDITOR <<EOF
404 echo editor started >"$(pwd)/.git/result"
405 exit 0
406 EOF
407
408 test_expect_success !FAIL_PREREQS,!AUTOIDENT 'do not fire editor when committer is bogus' '
409         >.git/result &&
410
411         echo >>negative &&
412         (
413                 sane_unset GIT_COMMITTER_EMAIL &&
414                 sane_unset GIT_COMMITTER_NAME &&
415                 GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
416                 export GIT_EDITOR &&
417                 test_must_fail git commit -e -m sample -a
418         ) &&
419         test_must_be_empty .git/result
420 '
421
422 test_expect_success 'do not fire editor if -m <msg> was given' '
423         echo tick >file &&
424         git add file &&
425         echo "editor not started" >.git/result &&
426         (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" git commit -m tick) &&
427         test "$(cat .git/result)" = "editor not started"
428 '
429
430 test_expect_success 'do not fire editor if -m "" was given' '
431         echo tock >file &&
432         git add file &&
433         echo "editor not started" >.git/result &&
434         (GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" \
435          git commit -m "" --allow-empty-message) &&
436         test "$(cat .git/result)" = "editor not started"
437 '
438
439 test_expect_success 'do not fire editor in the presence of conflicts' '
440
441         git clean -f &&
442         echo f >g &&
443         git add g &&
444         git commit -m "add g" &&
445         git branch second &&
446         echo main >g &&
447         echo g >h &&
448         git add g h &&
449         git commit -m "modify g and add h" &&
450         git checkout second &&
451         echo second >g &&
452         git add g &&
453         git commit -m second &&
454         # Must fail due to conflict
455         test_must_fail git cherry-pick -n main &&
456         echo "editor not started" >.git/result &&
457         (
458                 GIT_EDITOR="\"$(pwd)/.git/FAKE_EDITOR\"" &&
459                 export GIT_EDITOR &&
460                 test_must_fail git commit
461         ) &&
462         test "$(cat .git/result)" = "editor not started"
463 '
464
465 write_script .git/FAKE_EDITOR <<EOF
466 # kill -TERM command added below.
467 EOF
468
469 test_expect_success EXECKEEPSPID 'a SIGTERM should break locks' '
470         echo >>negative &&
471         ! "$SHELL_PATH" -c '\''
472           echo kill -TERM $$ >>.git/FAKE_EDITOR
473           GIT_EDITOR=.git/FAKE_EDITOR
474           export GIT_EDITOR
475           exec git commit -a'\'' &&
476         test ! -f .git/index.lock
477 '
478
479 rm -f .git/MERGE_MSG .git/COMMIT_EDITMSG
480 git reset -q --hard
481
482 test_expect_success 'Hand committing of a redundant merge removes dups' '
483
484         git rev-parse second main >expect &&
485         test_must_fail git merge second main &&
486         git checkout main g &&
487         EDITOR=: git commit -a &&
488         git cat-file commit HEAD >raw &&
489         sed -n -e "s/^parent //p" -e "/^$/q" raw >actual &&
490         test_cmp expect actual
491
492 '
493
494 test_expect_success 'A single-liner subject with a token plus colon is not a footer' '
495
496         git reset --hard &&
497         git commit -s -m "hello: kitty" --allow-empty &&
498         git cat-file commit HEAD >raw &&
499         sed -e "1,/^$/d" raw >actual &&
500         test_line_count = 3 actual
501
502 '
503
504 test_expect_success 'commit -s places sob on third line after two empty lines' '
505         git commit -s --allow-empty --allow-empty-message &&
506         cat <<-EOF >expect &&
507
508
509         Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>
510
511         EOF
512         sed -e "/^#/d" -e "s/^:.*//" .git/COMMIT_EDITMSG >actual &&
513         test_cmp expect actual
514 '
515
516 write_script .git/FAKE_EDITOR <<\EOF
517 mv "$1" "$1.orig"
518 (
519         echo message
520         cat "$1.orig"
521 ) >"$1"
522 EOF
523
524 echo '## Custom template' >template
525
526 try_commit () {
527         git reset --hard &&
528         echo >>negative &&
529         GIT_EDITOR=.git/FAKE_EDITOR git commit -a $* $use_template &&
530         case "$use_template" in
531         '')
532                 test_i18ngrep ! "^## Custom template" .git/COMMIT_EDITMSG ;;
533         *)
534                 test_i18ngrep "^## Custom template" .git/COMMIT_EDITMSG ;;
535         esac
536 }
537
538 try_commit_status_combo () {
539
540         test_expect_success 'commit' '
541                 try_commit "" &&
542                 test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
543         '
544
545         test_expect_success 'commit --status' '
546                 try_commit --status &&
547                 test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
548         '
549
550         test_expect_success 'commit --no-status' '
551                 try_commit --no-status &&
552                 test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
553         '
554
555         test_expect_success 'commit with commit.status = yes' '
556                 test_config commit.status yes &&
557                 try_commit "" &&
558                 test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
559         '
560
561         test_expect_success 'commit with commit.status = no' '
562                 test_config commit.status no &&
563                 try_commit "" &&
564                 test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
565         '
566
567         test_expect_success 'commit --status with commit.status = yes' '
568                 test_config commit.status yes &&
569                 try_commit --status &&
570                 test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
571         '
572
573         test_expect_success 'commit --no-status with commit.status = yes' '
574                 test_config commit.status yes &&
575                 try_commit --no-status &&
576                 test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
577         '
578
579         test_expect_success 'commit --status with commit.status = no' '
580                 test_config commit.status no &&
581                 try_commit --status &&
582                 test_i18ngrep "^# Changes to be committed:" .git/COMMIT_EDITMSG
583         '
584
585         test_expect_success 'commit --no-status with commit.status = no' '
586                 test_config commit.status no &&
587                 try_commit --no-status &&
588                 test_i18ngrep ! "^# Changes to be committed:" .git/COMMIT_EDITMSG
589         '
590
591 }
592
593 try_commit_status_combo
594
595 use_template="-t template"
596
597 try_commit_status_combo
598
599 test_expect_success 'commit --status with custom comment character' '
600         test_config core.commentchar ";" &&
601         try_commit --status &&
602         test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
603 '
604
605 test_expect_success 'switch core.commentchar' '
606         test_commit "#foo" foo &&
607         GIT_EDITOR=.git/FAKE_EDITOR git -c core.commentChar=auto commit --amend &&
608         test_i18ngrep "^; Changes to be committed:" .git/COMMIT_EDITMSG
609 '
610
611 test_expect_success 'switch core.commentchar but out of options' '
612         cat >text <<\EOF &&
613 # 1
614 ; 2
615 @ 3
616 ! 4
617 $ 5
618 % 6
619 ^ 7
620 & 8
621 | 9
622 : 10
623 EOF
624         git commit --amend -F text &&
625         (
626                 test_set_editor .git/FAKE_EDITOR &&
627                 test_must_fail git -c core.commentChar=auto commit --amend
628         )
629 '
630
631 test_done