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