5733d9cd3462a2448b3bb748e62dfe8452f9a733
   1#!/bin/sh
   2
   3test_description='git commit porcelain-ish'
   4
   5. ./test-lib.sh
   6
   7commit_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>]
  17check_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
  38test_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
  48test_expect_success 'output summary format: root-commit' '
  49        check_summary_oneline "" "a change"
  50'
  51
  52test_expect_success 'output summary format for commit with an empty diff' '
  53
  54        check_summary_oneline "" "empty" "--allow-empty"
  55'
  56
  57test_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
  77output_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
  86test_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
 107test_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
 119test_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
 129test_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
 141test_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
 154test_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
 165test_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
 176test_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
 183mesg_with_comment_and_newlines='
 184# text
 185
 186'
 187
 188test_expect_success 'prepare file with comment line and trailing newlines'  '
 189        printf "%s" "$mesg_with_comment_and_newlines" >expect
 190'
 191
 192test_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
 202test_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
 212test_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
 222test_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
 234test_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
 261test_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
 274test_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
 286test_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
 294echo "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
 299test_expect_success 'cleanup commit messages (strip option,-F,-e): output' '
 300        test_i18ncmp expect actual
 301'
 302
 303test_expect_success 'cleanup commit message (fail on invalid cleanup mode option)' '
 304        test_must_fail git commit --cleanup=non-existent
 305'
 306
 307test_expect_success 'cleanup commit message (fail on invalid cleanup mode configuration)' '
 308        test_must_fail git -c commit.cleanup=non-existent commit
 309'
 310
 311test_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
 321test_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
 331test_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
 341test_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
 351test_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
 358test_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
 365test_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
 372test_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
 380test_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
 387test_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
 400write_script .git/FAKE_EDITOR <<EOF
 401echo editor started >"$(pwd)/.git/result"
 402exit 0
 403EOF
 404
 405test_expect_success !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
 419test_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
 427test_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
 436test_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
 462write_script .git/FAKE_EDITOR <<EOF
 463# kill -TERM command added below.
 464EOF
 465
 466test_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
 476rm -f .git/MERGE_MSG .git/COMMIT_EDITMSG
 477git reset -q --hard
 478
 479test_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
 491test_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
 501test_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
 513write_script .git/FAKE_EDITOR <<\EOF
 514mv "$1" "$1.orig"
 515(
 516        echo message
 517        cat "$1.orig"
 518) >"$1"
 519EOF
 520
 521echo '## Custom template' >template
 522
 523try_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
 535try_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
 590try_commit_status_combo
 591
 592use_template="-t template"
 593
 594try_commit_status_combo
 595
 596test_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
 602test_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
 608test_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
 620EOF
 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
 628test_done