1#!/bin/sh
   2#
   3# Copyright (c) 2006 Junio C Hamano
   4#
   5test_description='various format-patch tests'
   7. ./test-lib.sh
   9. "$TEST_DIRECTORY"/lib-terminal.sh
  10test_expect_success setup '
  12        for i in 1 2 3 4 5 6 7 8 9 10; do echo "$i"; done >file &&
  14        cat file >elif &&
  15        git add file elif &&
  16        test_tick &&
  17        git commit -m Initial &&
  18        git checkout -b side &&
  19        for i in 1 2 5 6 A B C 7 8 9 10; do echo "$i"; done >file &&
  21        test_chmod +x elif &&
  22        test_tick &&
  23        git commit -m "Side changes #1" &&
  24        for i in D E F; do echo "$i"; done >>file &&
  26        git update-index file &&
  27        test_tick &&
  28        git commit -m "Side changes #2" &&
  29        git tag C2 &&
  30        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file &&
  32        git update-index file &&
  33        test_tick &&
  34        git commit -m "Side changes #3 with \\n backslash-n in it." &&
  35        git checkout master &&
  37        git diff-tree -p C2 | git apply --index &&
  38        test_tick &&
  39        git commit -m "Master accepts moral equivalent of #2"
  40'
  42test_expect_success "format-patch --ignore-if-in-upstream" '
  44        git format-patch --stdout master..side >patch0 &&
  46        cnt=`grep "^From " patch0 | wc -l` &&
  47        test $cnt = 3
  48'
  50test_expect_success "format-patch --ignore-if-in-upstream" '
  52        git format-patch --stdout \
  54                --ignore-if-in-upstream master..side >patch1 &&
  55        cnt=`grep "^From " patch1 | wc -l` &&
  56        test $cnt = 2
  57'
  59test_expect_success "format-patch doesn't consider merge commits" '
  61        git checkout -b slave master &&
  63        echo "Another line" >>file &&
  64        test_tick &&
  65        git commit -am "Slave change #1" &&
  66        echo "Yet another line" >>file &&
  67        test_tick &&
  68        git commit -am "Slave change #2" &&
  69        git checkout -b merger master &&
  70        test_tick &&
  71        git merge --no-ff slave &&
  72        cnt=`git format-patch -3 --stdout | grep "^From " | wc -l` &&
  73        test $cnt = 3
  74'
  75test_expect_success "format-patch result applies" '
  77        git checkout -b rebuild-0 master &&
  79        git am -3 patch0 &&
  80        cnt=`git rev-list master.. | wc -l` &&
  81        test $cnt = 2
  82'
  83test_expect_success "format-patch --ignore-if-in-upstream result applies" '
  85        git checkout -b rebuild-1 master &&
  87        git am -3 patch1 &&
  88        cnt=`git rev-list master.. | wc -l` &&
  89        test $cnt = 2
  90'
  91test_expect_success 'commit did not screw up the log message' '
  93        git cat-file commit side | grep "^Side .* with .* backslash-n"
  95'
  97test_expect_success 'format-patch did not screw up the log message' '
  99        grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
 101        grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
 102'
 104test_expect_success 'replay did not screw up the log message' '
 106        git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
 108'
 110test_expect_success 'extra headers' '
 112        git config format.headers "To: R. E. Cipient <rcipient@example.com>
 114" &&
 115        git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>
 116" &&
 117        git format-patch --stdout master..side > patch2 &&
 118        sed -e "/^\$/q" patch2 > hdrs2 &&
 119        grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs2 &&
 120        grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs2
 121'
 123test_expect_success 'extra headers without newlines' '
 125        git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 127        git config --add format.headers "Cc: S. E. Cipient <scipient@example.com>" &&
 128        git format-patch --stdout master..side >patch3 &&
 129        sed -e "/^\$/q" patch3 > hdrs3 &&
 130        grep "^To: R. E. Cipient <rcipient@example.com>\$" hdrs3 &&
 131        grep "^Cc: S. E. Cipient <scipient@example.com>\$" hdrs3
 132'
 134test_expect_success 'extra headers with multiple To:s' '
 136        git config --replace-all format.headers "To: R. E. Cipient <rcipient@example.com>" &&
 138        git config --add format.headers "To: S. E. Cipient <scipient@example.com>" &&
 139        git format-patch --stdout master..side > patch4 &&
 140        sed -e "/^\$/q" patch4 > hdrs4 &&
 141        grep "^To: R. E. Cipient <rcipient@example.com>,\$" hdrs4 &&
 142        grep "^ *S. E. Cipient <scipient@example.com>\$" hdrs4
 143'
 144test_expect_success 'additional command line cc' '
 146        git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 148        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 149        grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch5 &&
 150        grep "^ *S. E. Cipient <scipient@example.com>\$" patch5
 151'
 152test_expect_success 'command line headers' '
 154        git config --unset-all format.headers &&
 156        git format-patch --add-header="Cc: R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
 157        grep "^Cc: R. E. Cipient <rcipient@example.com>\$" patch6
 158'
 159test_expect_success 'configuration headers and command line headers' '
 161        git config --replace-all format.headers "Cc: R. E. Cipient <rcipient@example.com>" &&
 163        git format-patch --add-header="Cc: S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
 164        grep "^Cc: R. E. Cipient <rcipient@example.com>,\$" patch7 &&
 165        grep "^ *S. E. Cipient <scipient@example.com>\$" patch7
 166'
 167test_expect_success 'command line To: header' '
 169        git config --unset-all format.headers &&
 171        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 172        grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8
 173'
 174test_expect_success 'configuration To: header' '
 176        git config format.to "R. E. Cipient <rcipient@example.com>" &&
 178        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 179        grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9
 180'
 181test_expect_success '--no-to overrides config.to' '
 183        git config --replace-all format.to \
 185                "R. E. Cipient <rcipient@example.com>" &&
 186        git format-patch --no-to --stdout master..side |
 187        sed -e "/^\$/q" >patch10 &&
 188        ! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10
 189'
 190test_expect_success '--no-to and --to replaces config.to' '
 192        git config --replace-all format.to \
 194                "Someone <someone@out.there>" &&
 195        git format-patch --no-to --to="Someone Else <else@out.there>" \
 196                --stdout master..side |
 197        sed -e "/^\$/q" >patch11 &&
 198        ! grep "^To: Someone <someone@out.there>\$" patch11 &&
 199        grep "^To: Someone Else <else@out.there>\$" patch11
 200'
 201test_expect_success '--no-cc overrides config.cc' '
 203        git config --replace-all format.cc \
 205                "C. E. Cipient <rcipient@example.com>" &&
 206        git format-patch --no-cc --stdout master..side |
 207        sed -e "/^\$/q" >patch12 &&
 208        ! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12
 209'
 210test_expect_success '--no-add-headers overrides config.headers' '
 212        git config --replace-all format.headers \
 214                "Header1: B. E. Cipient <rcipient@example.com>" &&
 215        git format-patch --no-add-headers --stdout master..side |
 216        sed -e "/^\$/q" >patch13 &&
 217        ! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13
 218'
 219test_expect_success 'multiple files' '
 221        rm -rf patches/ &&
 223        git checkout side &&
 224        git format-patch -o patches/ master &&
 225        ls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch
 226'
 227check_threading () {
 229        expect="$1" &&
 230        shift &&
 231        (git format-patch --stdout "$@"; echo $? > status.out) |
 232        # Prints everything between the Message-ID and In-Reply-To,
 233        # and replaces all Message-ID-lookalikes by a sequence number
 234        perl -ne '
 235                if (/^(message-id|references|in-reply-to)/i) {
 236                        $printing = 1;
 237                } elsif (/^\S/) {
 238                        $printing = 0;
 239                }
 240                if ($printing) {
 241                        $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
 242                        for $k (keys %h) {s/$k/$h{$k}/};
 243                        print;
 244                }
 245                print "---\n" if /^From /i;
 246        ' > actual &&
 247        test 0 = "$(cat status.out)" &&
 248        test_cmp "$expect" actual
 249}
 250cat >> expect.no-threading <<EOF
 252---
 253---
 254---
 255EOF
 256test_expect_success 'no threading' '
 258        git checkout side &&
 259        check_threading expect.no-threading master
 260'
 261cat > expect.thread <<EOF
 263---
 264Message-Id: <0>
 265---
 266Message-Id: <1>
 267In-Reply-To: <0>
 268References: <0>
 269---
 270Message-Id: <2>
 271In-Reply-To: <0>
 272References: <0>
 273EOF
 274test_expect_success 'thread' '
 276        check_threading expect.thread --thread master
 277'
 278cat > expect.in-reply-to <<EOF
 280---
 281Message-Id: <0>
 282In-Reply-To: <1>
 283References: <1>
 284---
 285Message-Id: <2>
 286In-Reply-To: <1>
 287References: <1>
 288---
 289Message-Id: <3>
 290In-Reply-To: <1>
 291References: <1>
 292EOF
 293test_expect_success 'thread in-reply-to' '
 295        check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 296                --thread master
 297'
 298cat > expect.cover-letter <<EOF
 300---
 301Message-Id: <0>
 302---
 303Message-Id: <1>
 304In-Reply-To: <0>
 305References: <0>
 306---
 307Message-Id: <2>
 308In-Reply-To: <0>
 309References: <0>
 310---
 311Message-Id: <3>
 312In-Reply-To: <0>
 313References: <0>
 314EOF
 315test_expect_success 'thread cover-letter' '
 317        check_threading expect.cover-letter --cover-letter --thread master
 318'
 319cat > expect.cl-irt <<EOF
 321---
 322Message-Id: <0>
 323In-Reply-To: <1>
 324References: <1>
 325---
 326Message-Id: <2>
 327In-Reply-To: <0>
 328References: <1>
 329        <0>
 330---
 331Message-Id: <3>
 332In-Reply-To: <0>
 333References: <1>
 334        <0>
 335---
 336Message-Id: <4>
 337In-Reply-To: <0>
 338References: <1>
 339        <0>
 340EOF
 341test_expect_success 'thread cover-letter in-reply-to' '
 343        check_threading expect.cl-irt --cover-letter \
 344                --in-reply-to="<test.message>" --thread master
 345'
 346test_expect_success 'thread explicit shallow' '
 348        check_threading expect.cl-irt --cover-letter \
 349                --in-reply-to="<test.message>" --thread=shallow master
 350'
 351cat > expect.deep <<EOF
 353---
 354Message-Id: <0>
 355---
 356Message-Id: <1>
 357In-Reply-To: <0>
 358References: <0>
 359---
 360Message-Id: <2>
 361In-Reply-To: <1>
 362References: <0>
 363        <1>
 364EOF
 365test_expect_success 'thread deep' '
 367        check_threading expect.deep --thread=deep master
 368'
 369cat > expect.deep-irt <<EOF
 371---
 372Message-Id: <0>
 373In-Reply-To: <1>
 374References: <1>
 375---
 376Message-Id: <2>
 377In-Reply-To: <0>
 378References: <1>
 379        <0>
 380---
 381Message-Id: <3>
 382In-Reply-To: <2>
 383References: <1>
 384        <0>
 385        <2>
 386EOF
 387test_expect_success 'thread deep in-reply-to' '
 389        check_threading expect.deep-irt  --thread=deep \
 390                --in-reply-to="<test.message>" master
 391'
 392cat > expect.deep-cl <<EOF
 394---
 395Message-Id: <0>
 396---
 397Message-Id: <1>
 398In-Reply-To: <0>
 399References: <0>
 400---
 401Message-Id: <2>
 402In-Reply-To: <1>
 403References: <0>
 404        <1>
 405---
 406Message-Id: <3>
 407In-Reply-To: <2>
 408References: <0>
 409        <1>
 410        <2>
 411EOF
 412test_expect_success 'thread deep cover-letter' '
 414        check_threading expect.deep-cl --cover-letter --thread=deep master
 415'
 416cat > expect.deep-cl-irt <<EOF
 418---
 419Message-Id: <0>
 420In-Reply-To: <1>
 421References: <1>
 422---
 423Message-Id: <2>
 424In-Reply-To: <0>
 425References: <1>
 426        <0>
 427---
 428Message-Id: <3>
 429In-Reply-To: <2>
 430References: <1>
 431        <0>
 432        <2>
 433---
 434Message-Id: <4>
 435In-Reply-To: <3>
 436References: <1>
 437        <0>
 438        <2>
 439        <3>
 440EOF
 441test_expect_success 'thread deep cover-letter in-reply-to' '
 443        check_threading expect.deep-cl-irt --cover-letter \
 444                --in-reply-to="<test.message>" --thread=deep master
 445'
 446test_expect_success 'thread via config' '
 448        git config format.thread true &&
 449        check_threading expect.thread master
 450'
 451test_expect_success 'thread deep via config' '
 453        git config format.thread deep &&
 454        check_threading expect.deep master
 455'
 456test_expect_success 'thread config + override' '
 458        git config format.thread deep &&
 459        check_threading expect.thread --thread master
 460'
 461test_expect_success 'thread config + --no-thread' '
 463        git config format.thread deep &&
 464        check_threading expect.no-threading --no-thread master
 465'
 466test_expect_success 'excessive subject' '
 468        rm -rf patches/ &&
 470        git checkout side &&
 471        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
 472        git update-index file &&
 473        git commit -m "This is an excessively long subject line for a message due to the habit some projects have of not having a short, one-line subject at the start of the commit message, but rather sticking a whole paragraph right at the start as the only thing in the commit message. It had better not become the filename for the patch." &&
 474        git format-patch -o patches/ master..side &&
 475        ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
 476'
 477test_expect_success 'cover-letter inherits diff options' '
 479        git mv file foo &&
 481        git commit -m foo &&
 482        git format-patch --cover-letter -1 &&
 483        ! grep "file => foo .* 0 *\$" 0000-cover-letter.patch &&
 484        git format-patch --cover-letter -1 -M &&
 485        grep "file => foo .* 0 *\$" 0000-cover-letter.patch
 486'
 488cat > expect << EOF
 490  This is an excessively long subject line for a message due to the
 491    habit some projects have of not having a short, one-line subject at
 492    the start of the commit message, but rather sticking a whole
 493    paragraph right at the start as the only thing in the commit
 494    message. It had better not become the filename for the patch.
 495  foo
 496EOF
 498test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 500        git format-patch --cover-letter -2 &&
 502        sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output &&
 503        test_cmp expect output
 504'
 506cat > expect << EOF
 508---
 509 file |   16 ++++++++++++++++
 510 1 files changed, 16 insertions(+), 0 deletions(-)
 511diff --git a/file b/file
 513index 40f36c6..2dc5c23 100644
 514--- a/file
 515+++ b/file
 516@@ -13,4 +13,20 @@ C
 517 10
 518 D
 519 E
 520 F
 521+5
 522EOF
 523test_expect_success 'format-patch respects -U' '
 525        git format-patch -U4 -2 &&
 527        sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
 528        test_cmp expect output
 529'
 531cat > expect << EOF
 533diff --git a/file b/file
 535index 40f36c6..2dc5c23 100644
 536--- a/file
 537+++ b/file
 538@@ -14,3 +14,19 @@ C
 539 D
 540 E
 541 F
 542+5
 543EOF
 544test_expect_success 'format-patch -p suppresses stat' '
 546        git format-patch -p -2 &&
 548        sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
 549        test_cmp expect output
 550'
 552test_expect_success 'format-patch from a subdirectory (1)' '
 554        filename=$(
 555                rm -rf sub &&
 556                mkdir -p sub/dir &&
 557                cd sub/dir &&
 558                git format-patch -1
 559        ) &&
 560        case "$filename" in
 561        0*)
 562                ;; # ok
 563        *)
 564                echo "Oops? $filename"
 565                false
 566                ;;
 567        esac &&
 568        test -f "$filename"
 569'
 570test_expect_success 'format-patch from a subdirectory (2)' '
 572        filename=$(
 573                rm -rf sub &&
 574                mkdir -p sub/dir &&
 575                cd sub/dir &&
 576                git format-patch -1 -o ..
 577        ) &&
 578        case "$filename" in
 579        ../0*)
 580                ;; # ok
 581        *)
 582                echo "Oops? $filename"
 583                false
 584                ;;
 585        esac &&
 586        basename=$(expr "$filename" : ".*/\(.*\)") &&
 587        test -f "sub/$basename"
 588'
 589test_expect_success 'format-patch from a subdirectory (3)' '
 591        rm -f 0* &&
 592        filename=$(
 593                rm -rf sub &&
 594                mkdir -p sub/dir &&
 595                cd sub/dir &&
 596                git format-patch -1 -o "$TRASH_DIRECTORY"
 597        ) &&
 598        basename=$(expr "$filename" : ".*/\(.*\)") &&
 599        test -f "$basename"
 600'
 601test_expect_success 'format-patch --in-reply-to' '
 603        git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
 604        grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
 605        grep "^References: <baz@foo.bar>" patch8
 606'
 607test_expect_success 'format-patch --signoff' '
 609        git format-patch -1 --signoff --stdout |
 610        grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
 611'
 612echo "fatal: --name-only does not make sense" > expect.name-only
 614echo "fatal: --name-status does not make sense" > expect.name-status
 615echo "fatal: --check does not make sense" > expect.check
 616test_expect_success 'options no longer allowed for format-patch' '
 618        test_must_fail git format-patch --name-only 2> output &&
 619        test_cmp expect.name-only output &&
 620        test_must_fail git format-patch --name-status 2> output &&
 621        test_cmp expect.name-status output &&
 622        test_must_fail git format-patch --check 2> output &&
 623        test_cmp expect.check output'
 624test_expect_success 'format-patch --numstat should produce a patch' '
 626        git format-patch --numstat --stdout master..side > output &&
 627        test 6 = $(grep "^diff --git a/" output | wc -l)'
 628test_expect_success 'format-patch -- <path>' '
 630        git format-patch master..side -- file 2>error &&
 631        ! grep "Use .--" error
 632'
 633test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
 635        git format-patch --ignore-if-in-upstream HEAD
 636'
 637test_expect_success 'format-patch --signature' '
 639        git format-patch --stdout --signature="my sig" -1 >output &&
 640        grep "my sig" output
 641'
 642test_expect_success 'format-patch with format.signature config' '
 644        git config format.signature "config sig" &&
 645        git format-patch --stdout -1 >output &&
 646        grep "config sig" output
 647'
 648test_expect_success 'format-patch --signature overrides format.signature' '
 650        git config format.signature "config sig" &&
 651        git format-patch --stdout --signature="overrides" -1 >output &&
 652        ! grep "config sig" output &&
 653        grep "overrides" output
 654'
 655test_expect_success 'format-patch --no-signature ignores format.signature' '
 657        git config format.signature "config sig" &&
 658        git format-patch --stdout --signature="my sig" --no-signature \
 659                -1 >output &&
 660        ! grep "config sig" output &&
 661        ! grep "my sig" output &&
 662        ! grep "^-- \$" output
 663'
 664test_expect_success 'format-patch --signature --cover-letter' '
 666        git config --unset-all format.signature &&
 667        git format-patch --stdout --signature="my sig" --cover-letter \
 668                -1 >output &&
 669        grep "my sig" output &&
 670        test 2 = $(grep "my sig" output | wc -l)
 671'
 672test_expect_success 'format.signature="" supresses signatures' '
 674        git config format.signature "" &&
 675        git format-patch --stdout -1 >output &&
 676        ! grep "^-- \$" output
 677'
 678test_expect_success 'format-patch --no-signature supresses signatures' '
 680        git config --unset-all format.signature &&
 681        git format-patch --stdout --no-signature -1 >output &&
 682        ! grep "^-- \$" output
 683'
 684test_expect_success 'format-patch --signature="" supresses signatures' '
 686        git format-patch --signature="" -1 >output &&
 687        ! grep "^-- \$" output
 688'
 689test_expect_success TTY 'format-patch --stdout paginates' '
 691        rm -f pager_used &&
 692        (
 693                GIT_PAGER="wc >pager_used" &&
 694                export GIT_PAGER &&
 695                test_terminal git format-patch --stdout --all
 696        ) &&
 697        test_path_is_file pager_used
 698'
 699 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
 701        rm -f pager_used &&
 702        (
 703                GIT_PAGER="wc >pager_used" &&
 704                export GIT_PAGER &&
 705                test_terminal git --no-pager format-patch --stdout --all &&
 706                test_terminal git -c "pager.format-patch=false" format-patch --stdout --all
 707        ) &&
 708        test_path_is_missing pager_used &&
 709        test_path_is_missing .git/pager_used
 710'
 711test_done