t / t4014-format-patch.shon commit Merge branch 'en/checkout-mismerge-fix' (d1a251a)
   1#!/bin/sh
   2#
   3# Copyright (c) 2006 Junio C Hamano
   4#
   5
   6test_description='various format-patch tests'
   7
   8. ./test-lib.sh
   9. "$TEST_DIRECTORY"/lib-terminal.sh
  10
  11test_expect_success setup '
  12
  13        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
  20        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
  25        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
  31        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
  36        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
  41        git checkout side &&
  42        git checkout -b patchid &&
  43        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >file2 &&
  44        for i in 1 2 3 A 4 B C 7 8 9 10 D E F 5 6; do echo "$i"; done >file3 &&
  45        for i in 8 9 10; do echo "$i"; done >file &&
  46        git add file file2 file3 &&
  47        test_tick &&
  48        git commit -m "patchid 1" &&
  49        for i in 4 A B 7 8 9 10; do echo "$i"; done >file2 &&
  50        for i in 8 9 10 5 6; do echo "$i"; done >file3 &&
  51        git add file2 file3 &&
  52        test_tick &&
  53        git commit -m "patchid 2" &&
  54        for i in 10 5 6; do echo "$i"; done >file &&
  55        git add file &&
  56        test_tick &&
  57        git commit -m "patchid 3" &&
  58
  59        git checkout master
  60'
  61
  62test_expect_success "format-patch --ignore-if-in-upstream" '
  63
  64        git format-patch --stdout master..side >patch0 &&
  65        cnt=$(grep "^From " patch0 | wc -l) &&
  66        test $cnt = 3
  67
  68'
  69
  70test_expect_success "format-patch --ignore-if-in-upstream" '
  71
  72        git format-patch --stdout \
  73                --ignore-if-in-upstream master..side >patch1 &&
  74        cnt=$(grep "^From " patch1 | wc -l) &&
  75        test $cnt = 2
  76
  77'
  78
  79test_expect_success "format-patch --ignore-if-in-upstream handles tags" '
  80        git tag -a v1 -m tag side &&
  81        git tag -a v2 -m tag master &&
  82        git format-patch --stdout --ignore-if-in-upstream v2..v1 >patch1 &&
  83        cnt=$(grep "^From " patch1 | wc -l) &&
  84        test $cnt = 2
  85'
  86
  87test_expect_success "format-patch doesn't consider merge commits" '
  88
  89        git checkout -b slave master &&
  90        echo "Another line" >>file &&
  91        test_tick &&
  92        git commit -am "Slave change #1" &&
  93        echo "Yet another line" >>file &&
  94        test_tick &&
  95        git commit -am "Slave change #2" &&
  96        git checkout -b merger master &&
  97        test_tick &&
  98        git merge --no-ff slave &&
  99        cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) &&
 100        test $cnt = 3
 101'
 102
 103test_expect_success "format-patch result applies" '
 104
 105        git checkout -b rebuild-0 master &&
 106        git am -3 patch0 &&
 107        cnt=$(git rev-list master.. | wc -l) &&
 108        test $cnt = 2
 109'
 110
 111test_expect_success "format-patch --ignore-if-in-upstream result applies" '
 112
 113        git checkout -b rebuild-1 master &&
 114        git am -3 patch1 &&
 115        cnt=$(git rev-list master.. | wc -l) &&
 116        test $cnt = 2
 117'
 118
 119test_expect_success 'commit did not screw up the log message' '
 120
 121        git cat-file commit side | grep "^Side .* with .* backslash-n"
 122
 123'
 124
 125test_expect_success 'format-patch did not screw up the log message' '
 126
 127        grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
 128        grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
 129
 130'
 131
 132test_expect_success 'replay did not screw up the log message' '
 133
 134        git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
 135
 136'
 137
 138test_expect_success 'extra headers' '
 139
 140        git config format.headers "To: R E Cipient <rcipient@example.com>
 141" &&
 142        git config --add format.headers "Cc: S E Cipient <scipient@example.com>
 143" &&
 144        git format-patch --stdout master..side > patch2 &&
 145        sed -e "/^\$/q" patch2 > hdrs2 &&
 146        grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
 147        grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
 148
 149'
 150
 151test_expect_success 'extra headers without newlines' '
 152
 153        git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 154        git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
 155        git format-patch --stdout master..side >patch3 &&
 156        sed -e "/^\$/q" patch3 > hdrs3 &&
 157        grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
 158        grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
 159
 160'
 161
 162test_expect_success 'extra headers with multiple To:s' '
 163
 164        git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 165        git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
 166        git format-patch --stdout master..side > patch4 &&
 167        sed -e "/^\$/q" patch4 > hdrs4 &&
 168        grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
 169        grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
 170'
 171
 172test_expect_success 'additional command line cc (ascii)' '
 173
 174        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 175        git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 176        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 177        grep "^ *S E Cipient <scipient@example.com>\$" patch5
 178'
 179
 180test_expect_failure 'additional command line cc (rfc822)' '
 181
 182        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 183        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 184        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 185        grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
 186'
 187
 188test_expect_success 'command line headers' '
 189
 190        git config --unset-all format.headers &&
 191        git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
 192        grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
 193'
 194
 195test_expect_success 'configuration headers and command line headers' '
 196
 197        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 198        git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
 199        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
 200        grep "^ *S E Cipient <scipient@example.com>\$" patch7
 201'
 202
 203test_expect_success 'command line To: header (ascii)' '
 204
 205        git config --unset-all format.headers &&
 206        git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 207        grep "^To: R E Cipient <rcipient@example.com>\$" patch8
 208'
 209
 210test_expect_failure 'command line To: header (rfc822)' '
 211
 212        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 213        grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8
 214'
 215
 216test_expect_failure 'command line To: header (rfc2047)' '
 217
 218        git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 219        grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
 220'
 221
 222test_expect_success 'configuration To: header (ascii)' '
 223
 224        git config format.to "R E Cipient <rcipient@example.com>" &&
 225        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 226        grep "^To: R E Cipient <rcipient@example.com>\$" patch9
 227'
 228
 229test_expect_failure 'configuration To: header (rfc822)' '
 230
 231        git config format.to "R. E. Cipient <rcipient@example.com>" &&
 232        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 233        grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9
 234'
 235
 236test_expect_failure 'configuration To: header (rfc2047)' '
 237
 238        git config format.to "R Ä Cipient <rcipient@example.com>" &&
 239        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 240        grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
 241'
 242
 243# check_patch <patch>: Verify that <patch> looks like a half-sane
 244# patch email to avoid a false positive with !grep
 245check_patch () {
 246        grep -e "^From:" "$1" &&
 247        grep -e "^Date:" "$1" &&
 248        grep -e "^Subject:" "$1"
 249}
 250
 251test_expect_success 'format.from=false' '
 252
 253        git -c format.from=false format-patch --stdout master..side |
 254        sed -e "/^\$/q" >patch &&
 255        check_patch patch &&
 256        ! grep "^From: C O Mitter <committer@example.com>\$" patch
 257'
 258
 259test_expect_success 'format.from=true' '
 260
 261        git -c format.from=true format-patch --stdout master..side |
 262        sed -e "/^\$/q" >patch &&
 263        check_patch patch &&
 264        grep "^From: C O Mitter <committer@example.com>\$" patch
 265'
 266
 267test_expect_success 'format.from with address' '
 268
 269        git -c format.from="F R Om <from@example.com>" format-patch --stdout master..side |
 270        sed -e "/^\$/q" >patch &&
 271        check_patch patch &&
 272        grep "^From: F R Om <from@example.com>\$" patch
 273'
 274
 275test_expect_success '--no-from overrides format.from' '
 276
 277        git -c format.from="F R Om <from@example.com>" format-patch --no-from --stdout master..side |
 278        sed -e "/^\$/q" >patch &&
 279        check_patch patch &&
 280        ! grep "^From: F R Om <from@example.com>\$" patch
 281'
 282
 283test_expect_success '--from overrides format.from' '
 284
 285        git -c format.from="F R Om <from@example.com>" format-patch --from --stdout master..side |
 286        sed -e "/^\$/q" >patch &&
 287        check_patch patch &&
 288        ! grep "^From: F R Om <from@example.com>\$" patch
 289'
 290
 291test_expect_success '--no-to overrides config.to' '
 292
 293        git config --replace-all format.to \
 294                "R E Cipient <rcipient@example.com>" &&
 295        git format-patch --no-to --stdout master..side |
 296        sed -e "/^\$/q" >patch10 &&
 297        check_patch patch10 &&
 298        ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
 299'
 300
 301test_expect_success '--no-to and --to replaces config.to' '
 302
 303        git config --replace-all format.to \
 304                "Someone <someone@out.there>" &&
 305        git format-patch --no-to --to="Someone Else <else@out.there>" \
 306                --stdout master..side |
 307        sed -e "/^\$/q" >patch11 &&
 308        check_patch patch11 &&
 309        ! grep "^To: Someone <someone@out.there>\$" patch11 &&
 310        grep "^To: Someone Else <else@out.there>\$" patch11
 311'
 312
 313test_expect_success '--no-cc overrides config.cc' '
 314
 315        git config --replace-all format.cc \
 316                "C E Cipient <rcipient@example.com>" &&
 317        git format-patch --no-cc --stdout master..side |
 318        sed -e "/^\$/q" >patch12 &&
 319        check_patch patch12 &&
 320        ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
 321'
 322
 323test_expect_success '--no-add-header overrides config.headers' '
 324
 325        git config --replace-all format.headers \
 326                "Header1: B E Cipient <rcipient@example.com>" &&
 327        git format-patch --no-add-header --stdout master..side |
 328        sed -e "/^\$/q" >patch13 &&
 329        check_patch patch13 &&
 330        ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
 331'
 332
 333test_expect_success 'multiple files' '
 334
 335        rm -rf patches/ &&
 336        git checkout side &&
 337        git format-patch -o patches/ master &&
 338        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
 339'
 340
 341test_expect_success 'reroll count' '
 342        rm -fr patches &&
 343        git format-patch -o patches --cover-letter --reroll-count 4 master..side >list &&
 344        ! grep -v "^patches/v4-000[0-3]-" list &&
 345        sed -n -e "/^Subject: /p" $(cat list) >subjects &&
 346        ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
 347'
 348
 349test_expect_success 'reroll count (-v)' '
 350        rm -fr patches &&
 351        git format-patch -o patches --cover-letter -v4 master..side >list &&
 352        ! grep -v "^patches/v4-000[0-3]-" list &&
 353        sed -n -e "/^Subject: /p" $(cat list) >subjects &&
 354        ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
 355'
 356
 357check_threading () {
 358        expect="$1" &&
 359        shift &&
 360        (git format-patch --stdout "$@"; echo $? > status.out) |
 361        # Prints everything between the Message-ID and In-Reply-To,
 362        # and replaces all Message-ID-lookalikes by a sequence number
 363        perl -ne '
 364                if (/^(message-id|references|in-reply-to)/i) {
 365                        $printing = 1;
 366                } elsif (/^\S/) {
 367                        $printing = 0;
 368                }
 369                if ($printing) {
 370                        $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
 371                        for $k (keys %h) {s/$k/$h{$k}/};
 372                        print;
 373                }
 374                print "---\n" if /^From /i;
 375        ' > actual &&
 376        test 0 = "$(cat status.out)" &&
 377        test_cmp "$expect" actual
 378}
 379
 380cat >> expect.no-threading <<EOF
 381---
 382---
 383---
 384EOF
 385
 386test_expect_success 'no threading' '
 387        git checkout side &&
 388        check_threading expect.no-threading master
 389'
 390
 391cat > expect.thread <<EOF
 392---
 393Message-Id: <0>
 394---
 395Message-Id: <1>
 396In-Reply-To: <0>
 397References: <0>
 398---
 399Message-Id: <2>
 400In-Reply-To: <0>
 401References: <0>
 402EOF
 403
 404test_expect_success 'thread' '
 405        check_threading expect.thread --thread master
 406'
 407
 408cat > expect.in-reply-to <<EOF
 409---
 410Message-Id: <0>
 411In-Reply-To: <1>
 412References: <1>
 413---
 414Message-Id: <2>
 415In-Reply-To: <1>
 416References: <1>
 417---
 418Message-Id: <3>
 419In-Reply-To: <1>
 420References: <1>
 421EOF
 422
 423test_expect_success 'thread in-reply-to' '
 424        check_threading expect.in-reply-to --in-reply-to="<test.message>" \
 425                --thread master
 426'
 427
 428cat > expect.cover-letter <<EOF
 429---
 430Message-Id: <0>
 431---
 432Message-Id: <1>
 433In-Reply-To: <0>
 434References: <0>
 435---
 436Message-Id: <2>
 437In-Reply-To: <0>
 438References: <0>
 439---
 440Message-Id: <3>
 441In-Reply-To: <0>
 442References: <0>
 443EOF
 444
 445test_expect_success 'thread cover-letter' '
 446        check_threading expect.cover-letter --cover-letter --thread master
 447'
 448
 449cat > expect.cl-irt <<EOF
 450---
 451Message-Id: <0>
 452In-Reply-To: <1>
 453References: <1>
 454---
 455Message-Id: <2>
 456In-Reply-To: <0>
 457References: <1>
 458        <0>
 459---
 460Message-Id: <3>
 461In-Reply-To: <0>
 462References: <1>
 463        <0>
 464---
 465Message-Id: <4>
 466In-Reply-To: <0>
 467References: <1>
 468        <0>
 469EOF
 470
 471test_expect_success 'thread cover-letter in-reply-to' '
 472        check_threading expect.cl-irt --cover-letter \
 473                --in-reply-to="<test.message>" --thread master
 474'
 475
 476test_expect_success 'thread explicit shallow' '
 477        check_threading expect.cl-irt --cover-letter \
 478                --in-reply-to="<test.message>" --thread=shallow master
 479'
 480
 481cat > expect.deep <<EOF
 482---
 483Message-Id: <0>
 484---
 485Message-Id: <1>
 486In-Reply-To: <0>
 487References: <0>
 488---
 489Message-Id: <2>
 490In-Reply-To: <1>
 491References: <0>
 492        <1>
 493EOF
 494
 495test_expect_success 'thread deep' '
 496        check_threading expect.deep --thread=deep master
 497'
 498
 499cat > expect.deep-irt <<EOF
 500---
 501Message-Id: <0>
 502In-Reply-To: <1>
 503References: <1>
 504---
 505Message-Id: <2>
 506In-Reply-To: <0>
 507References: <1>
 508        <0>
 509---
 510Message-Id: <3>
 511In-Reply-To: <2>
 512References: <1>
 513        <0>
 514        <2>
 515EOF
 516
 517test_expect_success 'thread deep in-reply-to' '
 518        check_threading expect.deep-irt  --thread=deep \
 519                --in-reply-to="<test.message>" master
 520'
 521
 522cat > expect.deep-cl <<EOF
 523---
 524Message-Id: <0>
 525---
 526Message-Id: <1>
 527In-Reply-To: <0>
 528References: <0>
 529---
 530Message-Id: <2>
 531In-Reply-To: <1>
 532References: <0>
 533        <1>
 534---
 535Message-Id: <3>
 536In-Reply-To: <2>
 537References: <0>
 538        <1>
 539        <2>
 540EOF
 541
 542test_expect_success 'thread deep cover-letter' '
 543        check_threading expect.deep-cl --cover-letter --thread=deep master
 544'
 545
 546cat > expect.deep-cl-irt <<EOF
 547---
 548Message-Id: <0>
 549In-Reply-To: <1>
 550References: <1>
 551---
 552Message-Id: <2>
 553In-Reply-To: <0>
 554References: <1>
 555        <0>
 556---
 557Message-Id: <3>
 558In-Reply-To: <2>
 559References: <1>
 560        <0>
 561        <2>
 562---
 563Message-Id: <4>
 564In-Reply-To: <3>
 565References: <1>
 566        <0>
 567        <2>
 568        <3>
 569EOF
 570
 571test_expect_success 'thread deep cover-letter in-reply-to' '
 572        check_threading expect.deep-cl-irt --cover-letter \
 573                --in-reply-to="<test.message>" --thread=deep master
 574'
 575
 576test_expect_success 'thread via config' '
 577        test_config format.thread true &&
 578        check_threading expect.thread master
 579'
 580
 581test_expect_success 'thread deep via config' '
 582        test_config format.thread deep &&
 583        check_threading expect.deep master
 584'
 585
 586test_expect_success 'thread config + override' '
 587        test_config format.thread deep &&
 588        check_threading expect.thread --thread master
 589'
 590
 591test_expect_success 'thread config + --no-thread' '
 592        test_config format.thread deep &&
 593        check_threading expect.no-threading --no-thread master
 594'
 595
 596test_expect_success 'excessive subject' '
 597
 598        rm -rf patches/ &&
 599        git checkout side &&
 600        before=$(git hash-object file) &&
 601        before=$(git rev-parse --short $before) &&
 602        for i in 5 6 1 2 3 A 4 B C 7 8 9 10 D E F; do echo "$i"; done >>file &&
 603        after=$(git hash-object file) &&
 604        after=$(git rev-parse --short $after) &&
 605        git update-index file &&
 606        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." &&
 607        git format-patch -o patches/ master..side &&
 608        ls patches/0004-This-is-an-excessively-long-subject-line-for-a-messa.patch
 609'
 610
 611test_expect_success 'failure to write cover-letter aborts gracefully' '
 612        test_when_finished "rmdir 0000-cover-letter.patch" &&
 613        mkdir 0000-cover-letter.patch &&
 614        test_must_fail git format-patch --no-renames --cover-letter -1
 615'
 616
 617test_expect_success 'cover-letter inherits diff options' '
 618        git mv file foo &&
 619        git commit -m foo &&
 620        git format-patch --no-renames --cover-letter -1 &&
 621        check_patch 0000-cover-letter.patch &&
 622        ! grep "file => foo .* 0 *\$" 0000-cover-letter.patch &&
 623        git format-patch --cover-letter -1 -M &&
 624        grep "file => foo .* 0 *\$" 0000-cover-letter.patch
 625
 626'
 627
 628cat > expect << EOF
 629  This is an excessively long subject line for a message due to the
 630    habit some projects have of not having a short, one-line subject at
 631    the start of the commit message, but rather sticking a whole
 632    paragraph right at the start as the only thing in the commit
 633    message. It had better not become the filename for the patch.
 634  foo
 635
 636EOF
 637
 638test_expect_success 'shortlog of cover-letter wraps overly-long onelines' '
 639
 640        git format-patch --cover-letter -2 &&
 641        sed -e "1,/A U Thor/d" -e "/^\$/q" < 0000-cover-letter.patch > output &&
 642        test_cmp expect output
 643
 644'
 645
 646cat > expect << EOF
 647index $before..$after 100644
 648--- a/file
 649+++ b/file
 650@@ -13,4 +13,20 @@ C
 651 10
 652 D
 653 E
 654 F
 655+5
 656EOF
 657
 658test_expect_success 'format-patch respects -U' '
 659
 660        git format-patch -U4 -2 &&
 661        sed -e "1,/^diff/d" -e "/^+5/q" \
 662                <0001-This-is-an-excessively-long-subject-line-for-a-messa.patch \
 663                >output &&
 664        test_cmp expect output
 665
 666'
 667
 668cat > expect << EOF
 669
 670diff --git a/file b/file
 671index $before..$after 100644
 672--- a/file
 673+++ b/file
 674@@ -14,3 +14,19 @@ C
 675 D
 676 E
 677 F
 678+5
 679EOF
 680
 681test_expect_success 'format-patch -p suppresses stat' '
 682
 683        git format-patch -p -2 &&
 684        sed -e "1,/^\$/d" -e "/^+5/q" < 0001-This-is-an-excessively-long-subject-line-for-a-messa.patch > output &&
 685        test_cmp expect output
 686
 687'
 688
 689test_expect_success 'format-patch from a subdirectory (1)' '
 690        filename=$(
 691                rm -rf sub &&
 692                mkdir -p sub/dir &&
 693                cd sub/dir &&
 694                git format-patch -1
 695        ) &&
 696        case "$filename" in
 697        0*)
 698                ;; # ok
 699        *)
 700                echo "Oops? $filename"
 701                false
 702                ;;
 703        esac &&
 704        test -f "$filename"
 705'
 706
 707test_expect_success 'format-patch from a subdirectory (2)' '
 708        filename=$(
 709                rm -rf sub &&
 710                mkdir -p sub/dir &&
 711                cd sub/dir &&
 712                git format-patch -1 -o ..
 713        ) &&
 714        case "$filename" in
 715        ../0*)
 716                ;; # ok
 717        *)
 718                echo "Oops? $filename"
 719                false
 720                ;;
 721        esac &&
 722        basename=$(expr "$filename" : ".*/\(.*\)") &&
 723        test -f "sub/$basename"
 724'
 725
 726test_expect_success 'format-patch from a subdirectory (3)' '
 727        rm -f 0* &&
 728        filename=$(
 729                rm -rf sub &&
 730                mkdir -p sub/dir &&
 731                cd sub/dir &&
 732                git format-patch -1 -o "$TRASH_DIRECTORY"
 733        ) &&
 734        basename=$(expr "$filename" : ".*/\(.*\)") &&
 735        test -f "$basename"
 736'
 737
 738test_expect_success 'format-patch --in-reply-to' '
 739        git format-patch -1 --stdout --in-reply-to "baz@foo.bar" > patch8 &&
 740        grep "^In-Reply-To: <baz@foo.bar>" patch8 &&
 741        grep "^References: <baz@foo.bar>" patch8
 742'
 743
 744test_expect_success 'format-patch --signoff' '
 745        git format-patch -1 --signoff --stdout >out &&
 746        grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out
 747'
 748
 749test_expect_success 'format-patch --notes --signoff' '
 750        git notes --ref test add -m "test message" HEAD &&
 751        git format-patch -1 --signoff --stdout --notes=test >out &&
 752        # Three dashes must come after S-o-b
 753        ! sed "/^Signed-off-by: /q" out | grep "test message" &&
 754        sed "1,/^Signed-off-by: /d" out | grep "test message" &&
 755        # Notes message must come after three dashes
 756        ! sed "/^---$/q" out | grep "test message" &&
 757        sed "1,/^---$/d" out | grep "test message"
 758'
 759
 760test_expect_success 'format-patch notes output control' '
 761        git notes add -m "notes config message" HEAD &&
 762        test_when_finished git notes remove HEAD &&
 763
 764        git format-patch -1 --stdout >out &&
 765        ! grep "notes config message" out &&
 766        git format-patch -1 --stdout --notes >out &&
 767        grep "notes config message" out &&
 768        git format-patch -1 --stdout --no-notes >out &&
 769        ! grep "notes config message" out &&
 770        git format-patch -1 --stdout --notes --no-notes >out &&
 771        ! grep "notes config message" out &&
 772        git format-patch -1 --stdout --no-notes --notes >out &&
 773        grep "notes config message" out &&
 774
 775        test_config format.notes true &&
 776        git format-patch -1 --stdout >out &&
 777        grep "notes config message" out &&
 778        git format-patch -1 --stdout --notes >out &&
 779        grep "notes config message" out &&
 780        git format-patch -1 --stdout --no-notes >out &&
 781        ! grep "notes config message" out &&
 782        git format-patch -1 --stdout --notes --no-notes >out &&
 783        ! grep "notes config message" out &&
 784        git format-patch -1 --stdout --no-notes --notes >out &&
 785        grep "notes config message" out
 786'
 787
 788test_expect_success 'format-patch with multiple notes refs' '
 789        git notes --ref note1 add -m "this is note 1" HEAD &&
 790        test_when_finished git notes --ref note1 remove HEAD &&
 791        git notes --ref note2 add -m "this is note 2" HEAD &&
 792        test_when_finished git notes --ref note2 remove HEAD &&
 793
 794        git format-patch -1 --stdout >out &&
 795        ! grep "this is note 1" out &&
 796        ! grep "this is note 2" out &&
 797        git format-patch -1 --stdout --notes=note1 >out &&
 798        grep "this is note 1" out &&
 799        ! grep "this is note 2" out &&
 800        git format-patch -1 --stdout --notes=note2 >out &&
 801        ! grep "this is note 1" out &&
 802        grep "this is note 2" out &&
 803        git format-patch -1 --stdout --notes=note1 --notes=note2 >out &&
 804        grep "this is note 1" out &&
 805        grep "this is note 2" out &&
 806
 807        test_config format.notes note1 &&
 808        git format-patch -1 --stdout >out &&
 809        grep "this is note 1" out &&
 810        ! grep "this is note 2" out &&
 811        git format-patch -1 --stdout --no-notes >out &&
 812        ! grep "this is note 1" out &&
 813        ! grep "this is note 2" out &&
 814        git format-patch -1 --stdout --notes=note2 >out &&
 815        grep "this is note 1" out &&
 816        grep "this is note 2" out &&
 817        git format-patch -1 --stdout --no-notes --notes=note2 >out &&
 818        ! grep "this is note 1" out &&
 819        grep "this is note 2" out &&
 820
 821        git config --add format.notes note2 &&
 822        git format-patch -1 --stdout >out &&
 823        grep "this is note 1" out &&
 824        grep "this is note 2" out &&
 825        git format-patch -1 --stdout --no-notes >out &&
 826        ! grep "this is note 1" out &&
 827        ! grep "this is note 2" out
 828'
 829
 830echo "fatal: --name-only does not make sense" > expect.name-only
 831echo "fatal: --name-status does not make sense" > expect.name-status
 832echo "fatal: --check does not make sense" > expect.check
 833
 834test_expect_success 'options no longer allowed for format-patch' '
 835        test_must_fail git format-patch --name-only 2> output &&
 836        test_i18ncmp expect.name-only output &&
 837        test_must_fail git format-patch --name-status 2> output &&
 838        test_i18ncmp expect.name-status output &&
 839        test_must_fail git format-patch --check 2> output &&
 840        test_i18ncmp expect.check output'
 841
 842test_expect_success 'format-patch --numstat should produce a patch' '
 843        git format-patch --numstat --stdout master..side > output &&
 844        test 5 = $(grep "^diff --git a/" output | wc -l)'
 845
 846test_expect_success 'format-patch -- <path>' '
 847        git format-patch master..side -- file 2>error &&
 848        ! grep "Use .--" error
 849'
 850
 851test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
 852        git format-patch --ignore-if-in-upstream HEAD
 853'
 854
 855git_version="$(git --version | sed "s/.* //")"
 856
 857signature() {
 858        printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
 859}
 860
 861test_expect_success 'format-patch default signature' '
 862        git format-patch --stdout -1 | tail -n 3 >output &&
 863        signature >expect &&
 864        test_cmp expect output
 865'
 866
 867test_expect_success 'format-patch --signature' '
 868        git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output &&
 869        signature "my sig" >expect &&
 870        test_cmp expect output
 871'
 872
 873test_expect_success 'format-patch with format.signature config' '
 874        git config format.signature "config sig" &&
 875        git format-patch --stdout -1 >output &&
 876        grep "config sig" output
 877'
 878
 879test_expect_success 'format-patch --signature overrides format.signature' '
 880        git config format.signature "config sig" &&
 881        git format-patch --stdout --signature="overrides" -1 >output &&
 882        ! grep "config sig" output &&
 883        grep "overrides" output
 884'
 885
 886test_expect_success 'format-patch --no-signature ignores format.signature' '
 887        git config format.signature "config sig" &&
 888        git format-patch --stdout --signature="my sig" --no-signature \
 889                -1 >output &&
 890        check_patch output &&
 891        ! grep "config sig" output &&
 892        ! grep "my sig" output &&
 893        ! grep "^-- \$" output
 894'
 895
 896test_expect_success 'format-patch --signature --cover-letter' '
 897        git config --unset-all format.signature &&
 898        git format-patch --stdout --signature="my sig" --cover-letter \
 899                -1 >output &&
 900        grep "my sig" output &&
 901        test 2 = $(grep "my sig" output | wc -l)
 902'
 903
 904test_expect_success 'format.signature="" suppresses signatures' '
 905        git config format.signature "" &&
 906        git format-patch --stdout -1 >output &&
 907        check_patch output &&
 908        ! grep "^-- \$" output
 909'
 910
 911test_expect_success 'format-patch --no-signature suppresses signatures' '
 912        git config --unset-all format.signature &&
 913        git format-patch --stdout --no-signature -1 >output &&
 914        check_patch output &&
 915        ! grep "^-- \$" output
 916'
 917
 918test_expect_success 'format-patch --signature="" suppresses signatures' '
 919        git format-patch --stdout --signature="" -1 >output &&
 920        check_patch output &&
 921        ! grep "^-- \$" output
 922'
 923
 924test_expect_success 'prepare mail-signature input' '
 925        cat >mail-signature <<-\EOF
 926
 927        Test User <test.email@kernel.org>
 928        http://git.kernel.org/cgit/git/git.git
 929
 930        git.kernel.org/?p=git/git.git;a=summary
 931
 932        EOF
 933'
 934
 935test_expect_success '--signature-file=file works' '
 936        git format-patch --stdout --signature-file=mail-signature -1 >output &&
 937        check_patch output &&
 938        sed -e "1,/^-- \$/d" <output >actual &&
 939        {
 940                cat mail-signature && echo
 941        } >expect &&
 942        test_cmp expect actual
 943'
 944
 945test_expect_success 'format.signaturefile works' '
 946        test_config format.signaturefile mail-signature &&
 947        git format-patch --stdout -1 >output &&
 948        check_patch output &&
 949        sed -e "1,/^-- \$/d" <output >actual &&
 950        {
 951                cat mail-signature && echo
 952        } >expect &&
 953        test_cmp expect actual
 954'
 955
 956test_expect_success '--no-signature suppresses format.signaturefile ' '
 957        test_config format.signaturefile mail-signature &&
 958        git format-patch --stdout --no-signature -1 >output &&
 959        check_patch output &&
 960        ! grep "^-- \$" output
 961'
 962
 963test_expect_success '--signature-file overrides format.signaturefile' '
 964        cat >other-mail-signature <<-\EOF &&
 965        Use this other signature instead of mail-signature.
 966        EOF
 967        test_config format.signaturefile mail-signature &&
 968        git format-patch --stdout \
 969                        --signature-file=other-mail-signature -1 >output &&
 970        check_patch output &&
 971        sed -e "1,/^-- \$/d" <output >actual &&
 972        {
 973                cat other-mail-signature && echo
 974        } >expect &&
 975        test_cmp expect actual
 976'
 977
 978test_expect_success '--signature overrides format.signaturefile' '
 979        test_config format.signaturefile mail-signature &&
 980        git format-patch --stdout --signature="my sig" -1 >output &&
 981        check_patch output &&
 982        grep "my sig" output
 983'
 984
 985test_expect_success TTY 'format-patch --stdout paginates' '
 986        rm -f pager_used &&
 987        test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
 988        test_path_is_file pager_used
 989'
 990
 991 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
 992        rm -f pager_used &&
 993        test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
 994        test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
 995        test_path_is_missing pager_used &&
 996        test_path_is_missing .git/pager_used
 997'
 998
 999test_expect_success 'format-patch handles multi-line subjects' '
1000        rm -rf patches/ &&
1001        echo content >>file &&
1002        for i in one two three; do echo $i; done >msg &&
1003        git add file &&
1004        git commit -F msg &&
1005        git format-patch -o patches -1 &&
1006        grep ^Subject: patches/0001-one.patch >actual &&
1007        echo "Subject: [PATCH] one two three" >expect &&
1008        test_cmp expect actual
1009'
1010
1011test_expect_success 'format-patch handles multi-line encoded subjects' '
1012        rm -rf patches/ &&
1013        echo content >>file &&
1014        for i in en två tre; do echo $i; done >msg &&
1015        git add file &&
1016        git commit -F msg &&
1017        git format-patch -o patches -1 &&
1018        grep ^Subject: patches/0001-en.patch >actual &&
1019        echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
1020        test_cmp expect actual
1021'
1022
1023M8="foo bar "
1024M64=$M8$M8$M8$M8$M8$M8$M8$M8
1025M512=$M64$M64$M64$M64$M64$M64$M64$M64
1026cat >expect <<'EOF'
1027Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1028 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1029 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1030 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1031 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
1032 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1033 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
1034EOF
1035test_expect_success 'format-patch wraps extremely long subject (ascii)' '
1036        echo content >>file &&
1037        git add file &&
1038        git commit -m "$M512" &&
1039        git format-patch --stdout -1 >patch &&
1040        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1041        test_cmp expect subject
1042'
1043
1044M8="föö bar "
1045M64=$M8$M8$M8$M8$M8$M8$M8$M8
1046M512=$M64$M64$M64$M64$M64$M64$M64$M64
1047cat >expect <<'EOF'
1048Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1049 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1050 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1051 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1052 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1053 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1054 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1055 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1056 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1057 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1058 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1059 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1060 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1061 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1062 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1063 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1064 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1065 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1066 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1067 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1068 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1069 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1070 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1071 =?UTF-8?q?bar?=
1072EOF
1073test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1074        rm -rf patches/ &&
1075        echo content >>file &&
1076        git add file &&
1077        git commit -m "$M512" &&
1078        git format-patch --stdout -1 >patch &&
1079        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1080        test_cmp expect subject
1081'
1082
1083check_author() {
1084        echo content >>file &&
1085        git add file &&
1086        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1087        git format-patch --stdout -1 >patch &&
1088        sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
1089        test_cmp expect actual
1090}
1091
1092cat >expect <<'EOF'
1093From: "Foo B. Bar" <author@example.com>
1094EOF
1095test_expect_success 'format-patch quotes dot in from-headers' '
1096        check_author "Foo B. Bar"
1097'
1098
1099cat >expect <<'EOF'
1100From: "Foo \"The Baz\" Bar" <author@example.com>
1101EOF
1102test_expect_success 'format-patch quotes double-quote in from-headers' '
1103        check_author "Foo \"The Baz\" Bar"
1104'
1105
1106cat >expect <<'EOF'
1107From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1108EOF
1109test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1110        check_author "Föo Bar"
1111'
1112
1113cat >expect <<'EOF'
1114From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1115EOF
1116test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1117        check_author "Föo B. Bar"
1118'
1119
1120cat >expect <<EOF
1121From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1122 <author@example.com>
1123EOF
1124test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1125        check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1126'
1127
1128cat >expect <<'EOF'
1129From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1130 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1131 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1132EOF
1133test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1134        check_author "Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1135'
1136
1137cat >expect <<'EOF'
1138From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1139 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1140 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1141EOF
1142test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1143        check_author "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1144'
1145
1146cat >expect <<'EOF'
1147From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1148 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1149 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1150 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1151 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1152EOF
1153test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1154        check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
1155'
1156
1157cat >expect <<'EOF'
1158Subject: header with . in it
1159EOF
1160test_expect_success 'subject lines do not have 822 atom-quoting' '
1161        echo content >>file &&
1162        git add file &&
1163        git commit -m "header with . in it" &&
1164        git format-patch -k -1 --stdout >patch &&
1165        grep ^Subject: patch >actual &&
1166        test_cmp expect actual
1167'
1168
1169cat >expect <<'EOF'
1170Subject: [PREFIX 1/1] header with . in it
1171EOF
1172test_expect_success 'subject prefixes have space prepended' '
1173        git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1174        grep ^Subject: patch >actual &&
1175        test_cmp expect actual
1176'
1177
1178cat >expect <<'EOF'
1179Subject: [1/1] header with . in it
1180EOF
1181test_expect_success 'empty subject prefix does not have extra space' '
1182        git format-patch -n -1 --stdout --subject-prefix= >patch &&
1183        grep ^Subject: patch >actual &&
1184        test_cmp expect actual
1185'
1186
1187test_expect_success '--rfc' '
1188        cat >expect <<-\EOF &&
1189        Subject: [RFC PATCH 1/1] header with . in it
1190        EOF
1191        git format-patch -n -1 --stdout --rfc >patch &&
1192        grep ^Subject: patch >actual &&
1193        test_cmp expect actual
1194'
1195
1196test_expect_success '--from=ident notices bogus ident' '
1197        test_must_fail git format-patch -1 --stdout --from=foo >patch
1198'
1199
1200test_expect_success '--from=ident replaces author' '
1201        git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1202        cat >expect <<-\EOF &&
1203        From: Me <me@example.com>
1204
1205        From: A U Thor <author@example.com>
1206
1207        EOF
1208        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1209        test_cmp expect patch.head
1210'
1211
1212test_expect_success '--from uses committer ident' '
1213        git format-patch -1 --stdout --from >patch &&
1214        cat >expect <<-\EOF &&
1215        From: C O Mitter <committer@example.com>
1216
1217        From: A U Thor <author@example.com>
1218
1219        EOF
1220        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1221        test_cmp expect patch.head
1222'
1223
1224test_expect_success '--from omits redundant in-body header' '
1225        git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1226        cat >expect <<-\EOF &&
1227        From: A U Thor <author@example.com>
1228
1229        EOF
1230        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1231        test_cmp expect patch.head
1232'
1233
1234test_expect_success 'in-body headers trigger content encoding' '
1235        test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1236        test_when_finished "git reset --hard HEAD^" &&
1237        git format-patch -1 --stdout --from >patch &&
1238        cat >expect <<-\EOF &&
1239        From: C O Mitter <committer@example.com>
1240        Content-Type: text/plain; charset=UTF-8
1241
1242        From: éxötìc <author@example.com>
1243
1244        EOF
1245        sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
1246        test_cmp expect patch.head
1247'
1248
1249append_signoff()
1250{
1251        C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1252        git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1253        sed -n -e "1,/^---$/p" append_signoff.patch |
1254                egrep -n "^Subject|Sign|^$"
1255}
1256
1257test_expect_success 'signoff: commit with no body' '
1258        append_signoff </dev/null >actual &&
1259        cat <<\EOF | sed "s/EOL$//" >expected &&
12604:Subject: [PATCH] EOL
12618:
12629:Signed-off-by: C O Mitter <committer@example.com>
1263EOF
1264        test_cmp expected actual
1265'
1266
1267test_expect_success 'signoff: commit with only subject' '
1268        echo subject | append_signoff >actual &&
1269        cat >expected <<\EOF &&
12704:Subject: [PATCH] subject
12718:
12729:Signed-off-by: C O Mitter <committer@example.com>
1273EOF
1274        test_cmp expected actual
1275'
1276
1277test_expect_success 'signoff: commit with only subject that does not end with NL' '
1278        printf subject | append_signoff >actual &&
1279        cat >expected <<\EOF &&
12804:Subject: [PATCH] subject
12818:
12829:Signed-off-by: C O Mitter <committer@example.com>
1283EOF
1284        test_cmp expected actual
1285'
1286
1287test_expect_success 'signoff: no existing signoffs' '
1288        append_signoff <<\EOF >actual &&
1289subject
1290
1291body
1292EOF
1293        cat >expected <<\EOF &&
12944:Subject: [PATCH] subject
12958:
129610:
129711:Signed-off-by: C O Mitter <committer@example.com>
1298EOF
1299        test_cmp expected actual
1300'
1301
1302test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1303        printf "subject\n\nbody" | append_signoff >actual &&
1304        cat >expected <<\EOF &&
13054:Subject: [PATCH] subject
13068:
130710:
130811:Signed-off-by: C O Mitter <committer@example.com>
1309EOF
1310        test_cmp expected actual
1311'
1312
1313test_expect_success 'signoff: some random signoff' '
1314        append_signoff <<\EOF >actual &&
1315subject
1316
1317body
1318
1319Signed-off-by: my@house
1320EOF
1321        cat >expected <<\EOF &&
13224:Subject: [PATCH] subject
13238:
132410:
132511:Signed-off-by: my@house
132612:Signed-off-by: C O Mitter <committer@example.com>
1327EOF
1328        test_cmp expected actual
1329'
1330
1331test_expect_success 'signoff: misc conforming footer elements' '
1332        append_signoff <<\EOF >actual &&
1333subject
1334
1335body
1336
1337Signed-off-by: my@house
1338(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1339Tested-by: Some One <someone@example.com>
1340Bug: 1234
1341EOF
1342        cat >expected <<\EOF &&
13434:Subject: [PATCH] subject
13448:
134510:
134611:Signed-off-by: my@house
134715:Signed-off-by: C O Mitter <committer@example.com>
1348EOF
1349        test_cmp expected actual
1350'
1351
1352test_expect_success 'signoff: some random signoff-alike' '
1353        append_signoff <<\EOF >actual &&
1354subject
1355
1356body
1357Fooled-by-me: my@house
1358EOF
1359        cat >expected <<\EOF &&
13604:Subject: [PATCH] subject
13618:
136211:
136312:Signed-off-by: C O Mitter <committer@example.com>
1364EOF
1365        test_cmp expected actual
1366'
1367
1368test_expect_success 'signoff: not really a signoff' '
1369        append_signoff <<\EOF >actual &&
1370subject
1371
1372I want to mention about Signed-off-by: here.
1373EOF
1374        cat >expected <<\EOF &&
13754:Subject: [PATCH] subject
13768:
13779:I want to mention about Signed-off-by: here.
137810:
137911:Signed-off-by: C O Mitter <committer@example.com>
1380EOF
1381        test_cmp expected actual
1382'
1383
1384test_expect_success 'signoff: not really a signoff (2)' '
1385        append_signoff <<\EOF >actual &&
1386subject
1387
1388My unfortunate
1389Signed-off-by: example happens to be wrapped here.
1390EOF
1391        cat >expected <<\EOF &&
13924:Subject: [PATCH] subject
13938:
139410:Signed-off-by: example happens to be wrapped here.
139511:Signed-off-by: C O Mitter <committer@example.com>
1396EOF
1397        test_cmp expected actual
1398'
1399
1400test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1401        append_signoff <<\EOF >actual &&
1402subject
1403
1404Signed-off-by: my@house
1405Signed-off-by: your@house
1406
1407A lot of houses.
1408EOF
1409        cat >expected <<\EOF &&
14104:Subject: [PATCH] subject
14118:
14129:Signed-off-by: my@house
141310:Signed-off-by: your@house
141411:
141513:
141614:Signed-off-by: C O Mitter <committer@example.com>
1417EOF
1418        test_cmp expected actual
1419'
1420
1421test_expect_success 'signoff: the same signoff at the end' '
1422        append_signoff <<\EOF >actual &&
1423subject
1424
1425body
1426
1427Signed-off-by: C O Mitter <committer@example.com>
1428EOF
1429        cat >expected <<\EOF &&
14304:Subject: [PATCH] subject
14318:
143210:
143311:Signed-off-by: C O Mitter <committer@example.com>
1434EOF
1435        test_cmp expected actual
1436'
1437
1438test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1439        printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1440                append_signoff >actual &&
1441        cat >expected <<\EOF &&
14424:Subject: [PATCH] subject
14438:
14449:Signed-off-by: C O Mitter <committer@example.com>
1445EOF
1446        test_cmp expected actual
1447'
1448
1449test_expect_success 'signoff: the same signoff NOT at the end' '
1450        append_signoff <<\EOF >actual &&
1451subject
1452
1453body
1454
1455Signed-off-by: C O Mitter <committer@example.com>
1456Signed-off-by: my@house
1457EOF
1458        cat >expected <<\EOF &&
14594:Subject: [PATCH] subject
14608:
146110:
146211:Signed-off-by: C O Mitter <committer@example.com>
146312:Signed-off-by: my@house
1464EOF
1465        test_cmp expected actual
1466'
1467
1468test_expect_success 'signoff: tolerate garbage in conforming footer' '
1469        append_signoff <<\EOF >actual &&
1470subject
1471
1472body
1473
1474Tested-by: my@house
1475Some Trash
1476Signed-off-by: C O Mitter <committer@example.com>
1477EOF
1478        cat >expected <<\EOF &&
14794:Subject: [PATCH] subject
14808:
148110:
148213:Signed-off-by: C O Mitter <committer@example.com>
1483EOF
1484        test_cmp expected actual
1485'
1486
1487test_expect_success 'signoff: respect trailer config' '
1488        append_signoff <<\EOF >actual &&
1489subject
1490
1491Myfooter: x
1492Some Trash
1493EOF
1494        cat >expected <<\EOF &&
14954:Subject: [PATCH] subject
14968:
149711:
149812:Signed-off-by: C O Mitter <committer@example.com>
1499EOF
1500        test_cmp expected actual &&
1501
1502        test_config trailer.Myfooter.ifexists add &&
1503        append_signoff <<\EOF >actual &&
1504subject
1505
1506Myfooter: x
1507Some Trash
1508EOF
1509        cat >expected <<\EOF &&
15104:Subject: [PATCH] subject
15118:
151211:Signed-off-by: C O Mitter <committer@example.com>
1513EOF
1514        test_cmp expected actual
1515'
1516
1517test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1518        append_signoff <<\EOF >actual &&
1519subject
1520
1521body
1522
1523Reviewed-id: Noone
1524Tested-by: my@house
1525Change-id: Ideadbeef
1526Signed-off-by: C O Mitter <committer@example.com>
1527Bug: 1234
1528EOF
1529        cat >expected <<\EOF &&
15304:Subject: [PATCH] subject
15318:
153210:
153314:Signed-off-by: C O Mitter <committer@example.com>
1534EOF
1535        test_cmp expected actual
1536'
1537
1538test_expect_success 'format patch ignores color.ui' '
1539        test_unconfig color.ui &&
1540        git format-patch --stdout -1 >expect &&
1541        test_config color.ui always &&
1542        git format-patch --stdout -1 >actual &&
1543        test_cmp expect actual
1544'
1545
1546test_expect_success 'cover letter using branch description (1)' '
1547        git checkout rebuild-1 &&
1548        test_config branch.rebuild-1.description hello &&
1549        git format-patch --stdout --cover-letter master >actual &&
1550        grep hello actual >/dev/null
1551'
1552
1553test_expect_success 'cover letter using branch description (2)' '
1554        git checkout rebuild-1 &&
1555        test_config branch.rebuild-1.description hello &&
1556        git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1557        grep hello actual >/dev/null
1558'
1559
1560test_expect_success 'cover letter using branch description (3)' '
1561        git checkout rebuild-1 &&
1562        test_config branch.rebuild-1.description hello &&
1563        git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
1564        grep hello actual >/dev/null
1565'
1566
1567test_expect_success 'cover letter using branch description (4)' '
1568        git checkout rebuild-1 &&
1569        test_config branch.rebuild-1.description hello &&
1570        git format-patch --stdout --cover-letter master.. >actual &&
1571        grep hello actual >/dev/null
1572'
1573
1574test_expect_success 'cover letter using branch description (5)' '
1575        git checkout rebuild-1 &&
1576        test_config branch.rebuild-1.description hello &&
1577        git format-patch --stdout --cover-letter -2 HEAD >actual &&
1578        grep hello actual >/dev/null
1579'
1580
1581test_expect_success 'cover letter using branch description (6)' '
1582        git checkout rebuild-1 &&
1583        test_config branch.rebuild-1.description hello &&
1584        git format-patch --stdout --cover-letter -2 >actual &&
1585        grep hello actual >/dev/null
1586'
1587
1588test_expect_success 'cover letter with nothing' '
1589        git format-patch --stdout --cover-letter >actual &&
1590        test_line_count = 0 actual
1591'
1592
1593test_expect_success 'cover letter auto' '
1594        mkdir -p tmp &&
1595        test_when_finished "rm -rf tmp;
1596                git config --unset format.coverletter" &&
1597
1598        git config format.coverletter auto &&
1599        git format-patch -o tmp -1 >list &&
1600        test_line_count = 1 list &&
1601        git format-patch -o tmp -2 >list &&
1602        test_line_count = 3 list
1603'
1604
1605test_expect_success 'cover letter auto user override' '
1606        mkdir -p tmp &&
1607        test_when_finished "rm -rf tmp;
1608                git config --unset format.coverletter" &&
1609
1610        git config format.coverletter auto &&
1611        git format-patch -o tmp --cover-letter -1 >list &&
1612        test_line_count = 2 list &&
1613        git format-patch -o tmp --cover-letter -2 >list &&
1614        test_line_count = 3 list &&
1615        git format-patch -o tmp --no-cover-letter -1 >list &&
1616        test_line_count = 1 list &&
1617        git format-patch -o tmp --no-cover-letter -2 >list &&
1618        test_line_count = 2 list
1619'
1620
1621test_expect_success 'format-patch --zero-commit' '
1622        git format-patch --zero-commit --stdout v2..v1 >patch2 &&
1623        grep "^From " patch2 | sort | uniq >actual &&
1624        echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
1625        test_cmp expect actual
1626'
1627
1628test_expect_success 'From line has expected format' '
1629        git format-patch --stdout v2..v1 >patch2 &&
1630        grep "^From " patch2 >from &&
1631        grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
1632        test_cmp from filtered
1633'
1634
1635test_expect_success 'format-patch format.outputDirectory option' '
1636        test_config format.outputDirectory patches &&
1637        rm -fr patches &&
1638        git format-patch master..side &&
1639        test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l)
1640'
1641
1642test_expect_success 'format-patch -o overrides format.outputDirectory' '
1643        test_config format.outputDirectory patches &&
1644        rm -fr patches patchset &&
1645        git format-patch master..side -o patchset &&
1646        test_path_is_missing patches &&
1647        test_path_is_dir patchset
1648'
1649
1650test_expect_success 'format-patch --base' '
1651        git checkout patchid &&
1652        git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
1653        git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
1654        echo >expected &&
1655        echo "base-commit: $(git rev-parse HEAD~3)" >>expected &&
1656        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expected &&
1657        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expected &&
1658        signature >> expected &&
1659        test_cmp expected actual1 &&
1660        test_cmp expected actual2 &&
1661        echo >fail &&
1662        echo "base-commit: $(git rev-parse HEAD~3)" >>fail &&
1663        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1664        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1665        signature >> fail &&
1666        ! test_cmp fail actual1 &&
1667        ! test_cmp fail actual2
1668'
1669
1670test_expect_success 'format-patch --base errors out when base commit is in revision list' '
1671        test_must_fail git format-patch --base=HEAD -2 &&
1672        test_must_fail git format-patch --base=HEAD~1 -2 &&
1673        git format-patch --stdout --base=HEAD~2 -2 >patch &&
1674        grep "^base-commit:" patch >actual &&
1675        echo "base-commit: $(git rev-parse HEAD~2)" >expected &&
1676        test_cmp expected actual
1677'
1678
1679test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
1680        # For history as below:
1681        #
1682        #    ---Q---P---Z---Y---*---X
1683        #        \             /
1684        #         ------------W
1685        #
1686        # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
1687        git checkout -b topic1 master &&
1688        git rev-parse HEAD >commit-id-base &&
1689        test_commit P &&
1690        git rev-parse HEAD >commit-id-P &&
1691        test_commit Z &&
1692        git rev-parse HEAD >commit-id-Z &&
1693        test_commit Y &&
1694        git checkout -b topic2 master &&
1695        test_commit W &&
1696        git merge topic1 &&
1697        test_commit X &&
1698        test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
1699        test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
1700        git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
1701        grep "^base-commit:" patch >actual &&
1702        echo "base-commit: $(cat commit-id-base)" >expected &&
1703        test_cmp expected actual
1704'
1705
1706test_expect_success 'format-patch --base=auto' '
1707        git checkout -b upstream master &&
1708        git checkout -b local upstream &&
1709        git branch --set-upstream-to=upstream &&
1710        test_commit N1 &&
1711        test_commit N2 &&
1712        git format-patch --stdout --base=auto -2 >patch &&
1713        grep "^base-commit:" patch >actual &&
1714        echo "base-commit: $(git rev-parse upstream)" >expected &&
1715        test_cmp expected actual
1716'
1717
1718test_expect_success 'format-patch errors out when history involves criss-cross' '
1719        # setup criss-cross history
1720        #
1721        #   B---M1---D
1722        #  / \ /
1723        # A   X
1724        #  \ / \
1725        #   C---M2---E
1726        #
1727        git checkout master &&
1728        test_commit A &&
1729        git checkout -b xb master &&
1730        test_commit B &&
1731        git checkout -b xc master &&
1732        test_commit C &&
1733        git checkout -b xbc xb -- &&
1734        git merge xc &&
1735        git checkout -b xcb xc -- &&
1736        git branch --set-upstream-to=xbc &&
1737        git merge xb &&
1738        git checkout xbc &&
1739        test_commit D &&
1740        git checkout xcb &&
1741        test_commit E &&
1742        test_must_fail  git format-patch --base=auto -1
1743'
1744
1745test_expect_success 'format-patch format.useAutoBaseoption' '
1746        test_when_finished "git config --unset format.useAutoBase" &&
1747        git checkout local &&
1748        git config format.useAutoBase true &&
1749        git format-patch --stdout -1 >patch &&
1750        grep "^base-commit:" patch >actual &&
1751        echo "base-commit: $(git rev-parse upstream)" >expected &&
1752        test_cmp expected actual
1753'
1754
1755test_expect_success 'format-patch --base overrides format.useAutoBase' '
1756        test_when_finished "git config --unset format.useAutoBase" &&
1757        git config format.useAutoBase true &&
1758        git format-patch --stdout --base=HEAD~1 -1 >patch &&
1759        grep "^base-commit:" patch >actual &&
1760        echo "base-commit: $(git rev-parse HEAD~1)" >expected &&
1761        test_cmp expected actual
1762'
1763
1764test_expect_success 'format-patch --base with --attach' '
1765        git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
1766        sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
1767                patch >actual &&
1768        test_write_lines 1 2 >expect &&
1769        test_cmp expect actual
1770'
1771test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
1772        test_when_finished "rm -fr patches" &&
1773        git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
1774        ! egrep "^--+mimemime" patches/0000*.patch &&
1775        egrep "^--+mimemime$" patches/0001*.patch >output &&
1776        test_line_count = 2 output &&
1777        egrep "^--+mimemime--$" patches/0001*.patch >output &&
1778        test_line_count = 1 output
1779'
1780
1781test_expect_success 'format-patch --pretty=mboxrd' '
1782        sp=" " &&
1783        cat >msg <<-INPUT_END &&
1784        mboxrd should escape the body
1785
1786        From could trip up a loose mbox parser
1787        >From extra escape for reversibility
1788        >>From extra escape for reversibility 2
1789        from lower case not escaped
1790        Fromm bad speling not escaped
1791         From with leading space not escaped
1792
1793        F
1794        From
1795        From$sp
1796        From    $sp
1797        From    $sp
1798        INPUT_END
1799
1800        cat >expect <<-INPUT_END &&
1801        >From could trip up a loose mbox parser
1802        >>From extra escape for reversibility
1803        >>>From extra escape for reversibility 2
1804        from lower case not escaped
1805        Fromm bad speling not escaped
1806         From with leading space not escaped
1807
1808        F
1809        From
1810        From
1811        From
1812        From
1813        INPUT_END
1814
1815        C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
1816        git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
1817        git grep -h --no-index -A11 \
1818                "^>From could trip up a loose mbox parser" patch >actual &&
1819        test_cmp expect actual
1820'
1821
1822test_expect_success 'interdiff: setup' '
1823        git checkout -b boop master &&
1824        test_commit fnorp blorp &&
1825        test_commit fleep blorp
1826'
1827
1828test_expect_success 'interdiff: cover-letter' '
1829        sed "y/q/ /" >expect <<-\EOF &&
1830        +fleep
1831        --q
1832        EOF
1833        git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1834        test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1835        test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
1836        sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1837        test_cmp expect actual
1838'
1839
1840test_expect_success 'interdiff: reroll-count' '
1841        git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
1842        test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
1843'
1844
1845test_expect_success 'interdiff: solo-patch' '
1846        cat >expect <<-\EOF &&
1847          +fleep
1848
1849        EOF
1850        git format-patch --interdiff=boop~2 -1 boop &&
1851        test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
1852        sed "1,/^  @@ /d; /^$/q" <0001-fleep.patch >actual &&
1853        test_cmp expect actual
1854'
1855
1856test_done