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