c07d868491bbbd2887931d8afd19d662a4ac5272
   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        cnt=$(grep "^From " patch0 | wc -l) &&
  64        test $cnt = 3
  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        cnt=$(grep "^From " patch1 | wc -l) &&
  71        test $cnt = 2
  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        cnt=$(grep "^From " patch1 | wc -l) &&
  79        test $cnt = 2
  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        cnt=$(git format-patch -3 --stdout | grep "^From " | wc -l) &&
  94        test $cnt = 3
  95'
  96
  97test_expect_success 'format-patch result applies' '
  98        git checkout -b rebuild-0 master &&
  99        git am -3 patch0 &&
 100        cnt=$(git rev-list master.. | wc -l) &&
 101        test $cnt = 2
 102'
 103
 104test_expect_success 'format-patch --ignore-if-in-upstream result applies' '
 105        git checkout -b rebuild-1 master &&
 106        git am -3 patch1 &&
 107        cnt=$(git rev-list master.. | wc -l) &&
 108        test $cnt = 2
 109'
 110
 111test_expect_success 'commit did not screw up the log message' '
 112        git cat-file commit side | grep "^Side .* with .* backslash-n"
 113'
 114
 115test_expect_success 'format-patch did not screw up the log message' '
 116        grep "^Subject: .*Side changes #3 with .* backslash-n" patch0 &&
 117        grep "^Subject: .*Side changes #3 with .* backslash-n" patch1
 118'
 119
 120test_expect_success 'replay did not screw up the log message' '
 121        git cat-file commit rebuild-1 | grep "^Side .* with .* backslash-n"
 122'
 123
 124test_expect_success 'extra headers' '
 125        git config format.headers "To: R E Cipient <rcipient@example.com>
 126" &&
 127        git config --add format.headers "Cc: S E Cipient <scipient@example.com>
 128" &&
 129        git format-patch --stdout master..side >patch2 &&
 130        sed -e "/^\$/q" patch2 >hdrs2 &&
 131        grep "^To: R E Cipient <rcipient@example.com>\$" hdrs2 &&
 132        grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs2
 133'
 134
 135test_expect_success 'extra headers without newlines' '
 136        git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 137        git config --add format.headers "Cc: S E Cipient <scipient@example.com>" &&
 138        git format-patch --stdout master..side >patch3 &&
 139        sed -e "/^\$/q" patch3 >hdrs3 &&
 140        grep "^To: R E Cipient <rcipient@example.com>\$" hdrs3 &&
 141        grep "^Cc: S E Cipient <scipient@example.com>\$" hdrs3
 142'
 143
 144test_expect_success 'extra headers with multiple To:s' '
 145        git config --replace-all format.headers "To: R E Cipient <rcipient@example.com>" &&
 146        git config --add format.headers "To: S E Cipient <scipient@example.com>" &&
 147        git format-patch --stdout master..side >patch4 &&
 148        sed -e "/^\$/q" patch4 >hdrs4 &&
 149        grep "^To: R E Cipient <rcipient@example.com>,\$" hdrs4 &&
 150        grep "^ *S E Cipient <scipient@example.com>\$" hdrs4
 151'
 152
 153test_expect_success 'additional command line cc (ascii)' '
 154        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 155        git format-patch --cc="S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 156        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 157        grep "^ *S E Cipient <scipient@example.com>\$" patch5
 158'
 159
 160test_expect_failure 'additional command line cc (rfc822)' '
 161        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 162        git format-patch --cc="S. E. Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch5 &&
 163        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch5 &&
 164        grep "^ *\"S. E. Cipient\" <scipient@example.com>\$" patch5
 165'
 166
 167test_expect_success 'command line headers' '
 168        git config --unset-all format.headers &&
 169        git format-patch --add-header="Cc: R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch6 &&
 170        grep "^Cc: R E Cipient <rcipient@example.com>\$" patch6
 171'
 172
 173test_expect_success 'configuration headers and command line headers' '
 174        git config --replace-all format.headers "Cc: R E Cipient <rcipient@example.com>" &&
 175        git format-patch --add-header="Cc: S E Cipient <scipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch7 &&
 176        grep "^Cc: R E Cipient <rcipient@example.com>,\$" patch7 &&
 177        grep "^ *S E Cipient <scipient@example.com>\$" patch7
 178'
 179
 180test_expect_success 'command line To: header (ascii)' '
 181        git config --unset-all format.headers &&
 182        git format-patch --to="R E Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 183        grep "^To: R E Cipient <rcipient@example.com>\$" patch8
 184'
 185
 186test_expect_failure 'command line To: header (rfc822)' '
 187        git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 188        grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch8
 189'
 190
 191test_expect_failure 'command line To: header (rfc2047)' '
 192        git format-patch --to="R Ä Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 &&
 193        grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch8
 194'
 195
 196test_expect_success 'configuration To: header (ascii)' '
 197        git config format.to "R E Cipient <rcipient@example.com>" &&
 198        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 199        grep "^To: R E Cipient <rcipient@example.com>\$" patch9
 200'
 201
 202test_expect_failure 'configuration To: header (rfc822)' '
 203        git config format.to "R. E. Cipient <rcipient@example.com>" &&
 204        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 205        grep "^To: \"R. E. Cipient\" <rcipient@example.com>\$" patch9
 206'
 207
 208test_expect_failure 'configuration To: header (rfc2047)' '
 209        git config format.to "R Ä Cipient <rcipient@example.com>" &&
 210        git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 &&
 211        grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= <rcipient@example.com>\$" patch9
 212'
 213
 214# check_patch <patch>: Verify that <patch> looks like a half-sane
 215# patch email to avoid a false positive with !grep
 216check_patch () {
 217        grep -e "^From:" "$1" &&
 218        grep -e "^Date:" "$1" &&
 219        grep -e "^Subject:" "$1"
 220}
 221
 222test_expect_success 'format.from=false' '
 223        git -c format.from=false format-patch --stdout master..side |
 224        sed -e "/^\$/q" >patch &&
 225        check_patch patch &&
 226        ! grep "^From: C O Mitter <committer@example.com>\$" patch
 227'
 228
 229test_expect_success 'format.from=true' '
 230        git -c format.from=true format-patch --stdout master..side |
 231        sed -e "/^\$/q" >patch &&
 232        check_patch patch &&
 233        grep "^From: C O Mitter <committer@example.com>\$" patch
 234'
 235
 236test_expect_success 'format.from with address' '
 237        git -c format.from="F R Om <from@example.com>" format-patch --stdout master..side |
 238        sed -e "/^\$/q" >patch &&
 239        check_patch patch &&
 240        grep "^From: F R Om <from@example.com>\$" patch
 241'
 242
 243test_expect_success '--no-from overrides format.from' '
 244        git -c format.from="F R Om <from@example.com>" format-patch --no-from --stdout master..side |
 245        sed -e "/^\$/q" >patch &&
 246        check_patch patch &&
 247        ! grep "^From: F R Om <from@example.com>\$" patch
 248'
 249
 250test_expect_success '--from overrides format.from' '
 251        git -c format.from="F R Om <from@example.com>" format-patch --from --stdout master..side |
 252        sed -e "/^\$/q" >patch &&
 253        check_patch patch &&
 254        ! grep "^From: F R Om <from@example.com>\$" patch
 255'
 256
 257test_expect_success '--no-to overrides config.to' '
 258        git config --replace-all format.to \
 259                "R E Cipient <rcipient@example.com>" &&
 260        git format-patch --no-to --stdout master..side |
 261        sed -e "/^\$/q" >patch10 &&
 262        check_patch patch10 &&
 263        ! grep "^To: R E Cipient <rcipient@example.com>\$" patch10
 264'
 265
 266test_expect_success '--no-to and --to replaces config.to' '
 267        git config --replace-all format.to \
 268                "Someone <someone@out.there>" &&
 269        git format-patch --no-to --to="Someone Else <else@out.there>" \
 270                --stdout master..side |
 271        sed -e "/^\$/q" >patch11 &&
 272        check_patch patch11 &&
 273        ! grep "^To: Someone <someone@out.there>\$" patch11 &&
 274        grep "^To: Someone Else <else@out.there>\$" patch11
 275'
 276
 277test_expect_success '--no-cc overrides config.cc' '
 278        git config --replace-all format.cc \
 279                "C E Cipient <rcipient@example.com>" &&
 280        git format-patch --no-cc --stdout master..side |
 281        sed -e "/^\$/q" >patch12 &&
 282        check_patch patch12 &&
 283        ! grep "^Cc: C E Cipient <rcipient@example.com>\$" patch12
 284'
 285
 286test_expect_success '--no-add-header overrides config.headers' '
 287        git config --replace-all format.headers \
 288                "Header1: B E Cipient <rcipient@example.com>" &&
 289        git format-patch --no-add-header --stdout master..side |
 290        sed -e "/^\$/q" >patch13 &&
 291        check_patch patch13 &&
 292        ! grep "^Header1: B E Cipient <rcipient@example.com>\$" patch13
 293'
 294
 295test_expect_success 'multiple files' '
 296        rm -rf patches/ &&
 297        git checkout side &&
 298        git format-patch -o patches/ master &&
 299        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
 300'
 301
 302test_expect_success 'reroll count' '
 303        rm -fr patches &&
 304        git format-patch -o patches --cover-letter --reroll-count 4 master..side >list &&
 305        ! grep -v "^patches/v4-000[0-3]-" list &&
 306        sed -n -e "/^Subject: /p" $(cat list) >subjects &&
 307        ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
 308'
 309
 310test_expect_success 'reroll count (-v)' '
 311        rm -fr patches &&
 312        git format-patch -o patches --cover-letter -v4 master..side >list &&
 313        ! grep -v "^patches/v4-000[0-3]-" list &&
 314        sed -n -e "/^Subject: /p" $(cat list) >subjects &&
 315        ! grep -v "^Subject: \[PATCH v4 [0-3]/3\] " subjects
 316'
 317
 318check_threading () {
 319        expect="$1" &&
 320        shift &&
 321        (git format-patch --stdout "$@"; echo $? >status.out) |
 322        # Prints everything between the Message-ID and In-Reply-To,
 323        # and replaces all Message-ID-lookalikes by a sequence number
 324        perl -ne '
 325                if (/^(message-id|references|in-reply-to)/i) {
 326                        $printing = 1;
 327                } elsif (/^\S/) {
 328                        $printing = 0;
 329                }
 330                if ($printing) {
 331                        $h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});
 332                        for $k (keys %h) {s/$k/$h{$k}/};
 333                        print;
 334                }
 335                print "---\n" if /^From /i;
 336        ' >actual &&
 337        test 0 = "$(cat status.out)" &&
 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        test 5 = $(grep "^diff --git a/" output | wc -l)
 799'
 800
 801test_expect_success 'format-patch -- <path>' '
 802        git format-patch master..side -- file 2>error &&
 803        ! grep "Use .--" error
 804'
 805
 806test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
 807        git format-patch --ignore-if-in-upstream HEAD
 808'
 809
 810git_version="$(git --version | sed "s/.* //")"
 811
 812signature() {
 813        printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
 814}
 815
 816test_expect_success 'format-patch default signature' '
 817        git format-patch --stdout -1 | tail -n 3 >output &&
 818        signature >expect &&
 819        test_cmp expect output
 820'
 821
 822test_expect_success 'format-patch --signature' '
 823        git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output &&
 824        signature "my sig" >expect &&
 825        test_cmp expect output
 826'
 827
 828test_expect_success 'format-patch with format.signature config' '
 829        git config format.signature "config sig" &&
 830        git format-patch --stdout -1 >output &&
 831        grep "config sig" output
 832'
 833
 834test_expect_success 'format-patch --signature overrides format.signature' '
 835        git config format.signature "config sig" &&
 836        git format-patch --stdout --signature="overrides" -1 >output &&
 837        ! grep "config sig" output &&
 838        grep "overrides" output
 839'
 840
 841test_expect_success 'format-patch --no-signature ignores format.signature' '
 842        git config format.signature "config sig" &&
 843        git format-patch --stdout --signature="my sig" --no-signature \
 844                -1 >output &&
 845        check_patch output &&
 846        ! grep "config sig" output &&
 847        ! grep "my sig" output &&
 848        ! grep "^-- \$" output
 849'
 850
 851test_expect_success 'format-patch --signature --cover-letter' '
 852        git config --unset-all format.signature &&
 853        git format-patch --stdout --signature="my sig" --cover-letter \
 854                -1 >output &&
 855        grep "my sig" output &&
 856        test 2 = $(grep "my sig" output | wc -l)
 857'
 858
 859test_expect_success 'format.signature="" suppresses signatures' '
 860        git config format.signature "" &&
 861        git format-patch --stdout -1 >output &&
 862        check_patch output &&
 863        ! grep "^-- \$" output
 864'
 865
 866test_expect_success 'format-patch --no-signature suppresses signatures' '
 867        git config --unset-all format.signature &&
 868        git format-patch --stdout --no-signature -1 >output &&
 869        check_patch output &&
 870        ! grep "^-- \$" output
 871'
 872
 873test_expect_success 'format-patch --signature="" suppresses signatures' '
 874        git format-patch --stdout --signature="" -1 >output &&
 875        check_patch output &&
 876        ! grep "^-- \$" output
 877'
 878
 879test_expect_success 'prepare mail-signature input' '
 880        cat >mail-signature <<-\EOF
 881
 882        Test User <test.email@kernel.org>
 883        http://git.kernel.org/cgit/git/git.git
 884
 885        git.kernel.org/?p=git/git.git;a=summary
 886
 887        EOF
 888'
 889
 890test_expect_success '--signature-file=file works' '
 891        git format-patch --stdout --signature-file=mail-signature -1 >output &&
 892        check_patch output &&
 893        sed -e "1,/^-- \$/d" <output >actual &&
 894        {
 895                cat mail-signature && echo
 896        } >expect &&
 897        test_cmp expect actual
 898'
 899
 900test_expect_success 'format.signaturefile works' '
 901        test_config format.signaturefile mail-signature &&
 902        git format-patch --stdout -1 >output &&
 903        check_patch output &&
 904        sed -e "1,/^-- \$/d" <output >actual &&
 905        {
 906                cat mail-signature && echo
 907        } >expect &&
 908        test_cmp expect actual
 909'
 910
 911test_expect_success '--no-signature suppresses format.signaturefile ' '
 912        test_config format.signaturefile mail-signature &&
 913        git format-patch --stdout --no-signature -1 >output &&
 914        check_patch output &&
 915        ! grep "^-- \$" output
 916'
 917
 918test_expect_success '--signature-file overrides format.signaturefile' '
 919        cat >other-mail-signature <<-\EOF &&
 920        Use this other signature instead of mail-signature.
 921        EOF
 922        test_config format.signaturefile mail-signature &&
 923        git format-patch --stdout \
 924                        --signature-file=other-mail-signature -1 >output &&
 925        check_patch output &&
 926        sed -e "1,/^-- \$/d" <output >actual &&
 927        {
 928                cat other-mail-signature && echo
 929        } >expect &&
 930        test_cmp expect actual
 931'
 932
 933test_expect_success '--signature overrides format.signaturefile' '
 934        test_config format.signaturefile mail-signature &&
 935        git format-patch --stdout --signature="my sig" -1 >output &&
 936        check_patch output &&
 937        grep "my sig" output
 938'
 939
 940test_expect_success TTY 'format-patch --stdout paginates' '
 941        rm -f pager_used &&
 942        test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
 943        test_path_is_file pager_used
 944'
 945
 946 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
 947        rm -f pager_used &&
 948        test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
 949        test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
 950        test_path_is_missing pager_used &&
 951        test_path_is_missing .git/pager_used
 952'
 953
 954test_expect_success 'format-patch handles multi-line subjects' '
 955        rm -rf patches/ &&
 956        echo content >>file &&
 957        for i in one two three; do echo $i; done >msg &&
 958        git add file &&
 959        git commit -F msg &&
 960        git format-patch -o patches -1 &&
 961        grep ^Subject: patches/0001-one.patch >actual &&
 962        echo "Subject: [PATCH] one two three" >expect &&
 963        test_cmp expect actual
 964'
 965
 966test_expect_success 'format-patch handles multi-line encoded subjects' '
 967        rm -rf patches/ &&
 968        echo content >>file &&
 969        for i in en två tre; do echo $i; done >msg &&
 970        git add file &&
 971        git commit -F msg &&
 972        git format-patch -o patches -1 &&
 973        grep ^Subject: patches/0001-en.patch >actual &&
 974        echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
 975        test_cmp expect actual
 976'
 977
 978M8="foo bar "
 979M64=$M8$M8$M8$M8$M8$M8$M8$M8
 980M512=$M64$M64$M64$M64$M64$M64$M64$M64
 981cat >expect <<'EOF'
 982Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 983 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 984 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 985 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 986 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 987 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 988 foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 989EOF
 990test_expect_success 'format-patch wraps extremely long subject (ascii)' '
 991        echo content >>file &&
 992        git add file &&
 993        git commit -m "$M512" &&
 994        git format-patch --stdout -1 >patch &&
 995        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
 996        test_cmp expect subject
 997'
 998
 999M8="föö bar "
1000M64=$M8$M8$M8$M8$M8$M8$M8$M8
1001M512=$M64$M64$M64$M64$M64$M64$M64$M64
1002cat >expect <<'EOF'
1003Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1004 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1005 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1006 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1007 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1008 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1009 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1010 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1011 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1012 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1013 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1014 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1015 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1016 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1017 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1018 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1019 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1020 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1021 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1022 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1023 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1024 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1025 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1026 =?UTF-8?q?bar?=
1027EOF
1028test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1029        rm -rf patches/ &&
1030        echo content >>file &&
1031        git add file &&
1032        git commit -m "$M512" &&
1033        git format-patch --stdout -1 >patch &&
1034        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1035        test_cmp expect subject
1036'
1037
1038check_author() {
1039        echo content >>file &&
1040        git add file &&
1041        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1042        git format-patch --stdout -1 >patch &&
1043        sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
1044        test_cmp expect actual
1045}
1046
1047cat >expect <<'EOF'
1048From: "Foo B. Bar" <author@example.com>
1049EOF
1050test_expect_success 'format-patch quotes dot in from-headers' '
1051        check_author "Foo B. Bar"
1052'
1053
1054cat >expect <<'EOF'
1055From: "Foo \"The Baz\" Bar" <author@example.com>
1056EOF
1057test_expect_success 'format-patch quotes double-quote in from-headers' '
1058        check_author "Foo \"The Baz\" Bar"
1059'
1060
1061cat >expect <<'EOF'
1062From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1063EOF
1064test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1065        check_author "Föo Bar"
1066'
1067
1068cat >expect <<'EOF'
1069From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1070EOF
1071test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1072        check_author "Föo B. Bar"
1073'
1074
1075cat >expect <<EOF
1076From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1077 <author@example.com>
1078EOF
1079test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1080        check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1081'
1082
1083cat >expect <<'EOF'
1084From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1085 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1086 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1087EOF
1088test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1089        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"
1090'
1091
1092cat >expect <<'EOF'
1093From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1094 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1095 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1096EOF
1097test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1098        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"
1099'
1100
1101cat >expect <<'EOF'
1102From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1103 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1104 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1105 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1106 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1107EOF
1108test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1109        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"
1110'
1111
1112cat >expect <<'EOF'
1113Subject: header with . in it
1114EOF
1115test_expect_success 'subject lines do not have 822 atom-quoting' '
1116        echo content >>file &&
1117        git add file &&
1118        git commit -m "header with . in it" &&
1119        git format-patch -k -1 --stdout >patch &&
1120        grep ^Subject: patch >actual &&
1121        test_cmp expect actual
1122'
1123
1124cat >expect <<'EOF'
1125Subject: [PREFIX 1/1] header with . in it
1126EOF
1127test_expect_success 'subject prefixes have space prepended' '
1128        git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1129        grep ^Subject: patch >actual &&
1130        test_cmp expect actual
1131'
1132
1133cat >expect <<'EOF'
1134Subject: [1/1] header with . in it
1135EOF
1136test_expect_success 'empty subject prefix does not have extra space' '
1137        git format-patch -n -1 --stdout --subject-prefix= >patch &&
1138        grep ^Subject: patch >actual &&
1139        test_cmp expect actual
1140'
1141
1142test_expect_success '--rfc' '
1143        cat >expect <<-\EOF &&
1144        Subject: [RFC PATCH 1/1] header with . in it
1145        EOF
1146        git format-patch -n -1 --stdout --rfc >patch &&
1147        grep ^Subject: patch >actual &&
1148        test_cmp expect actual
1149'
1150
1151test_expect_success '--from=ident notices bogus ident' '
1152        test_must_fail git format-patch -1 --stdout --from=foo >patch
1153'
1154
1155test_expect_success '--from=ident replaces author' '
1156        git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1157        cat >expect <<-\EOF &&
1158        From: Me <me@example.com>
1159
1160        From: A U Thor <author@example.com>
1161
1162        EOF
1163        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1164        test_cmp expect patch.head
1165'
1166
1167test_expect_success '--from uses committer ident' '
1168        git format-patch -1 --stdout --from >patch &&
1169        cat >expect <<-\EOF &&
1170        From: C O Mitter <committer@example.com>
1171
1172        From: A U Thor <author@example.com>
1173
1174        EOF
1175        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1176        test_cmp expect patch.head
1177'
1178
1179test_expect_success '--from omits redundant in-body header' '
1180        git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1181        cat >expect <<-\EOF &&
1182        From: A U Thor <author@example.com>
1183
1184        EOF
1185        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1186        test_cmp expect patch.head
1187'
1188
1189test_expect_success 'in-body headers trigger content encoding' '
1190        test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1191        test_when_finished "git reset --hard HEAD^" &&
1192        git format-patch -1 --stdout --from >patch &&
1193        cat >expect <<-\EOF &&
1194        From: C O Mitter <committer@example.com>
1195        Content-Type: text/plain; charset=UTF-8
1196
1197        From: éxötìc <author@example.com>
1198
1199        EOF
1200        sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
1201        test_cmp expect patch.head
1202'
1203
1204append_signoff()
1205{
1206        C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1207        git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1208        sed -n -e "1,/^---$/p" append_signoff.patch |
1209                egrep -n "^Subject|Sign|^$"
1210}
1211
1212test_expect_success 'signoff: commit with no body' '
1213        append_signoff </dev/null >actual &&
1214        cat <<-\EOF | sed "s/EOL$//" >expect &&
1215        4:Subject: [PATCH] EOL
1216        8:
1217        9:Signed-off-by: C O Mitter <committer@example.com>
1218        EOF
1219        test_cmp expect actual
1220'
1221
1222test_expect_success 'signoff: commit with only subject' '
1223        echo subject | append_signoff >actual &&
1224        cat >expect <<-\EOF &&
1225        4:Subject: [PATCH] subject
1226        8:
1227        9:Signed-off-by: C O Mitter <committer@example.com>
1228        EOF
1229        test_cmp expect actual
1230'
1231
1232test_expect_success 'signoff: commit with only subject that does not end with NL' '
1233        printf subject | append_signoff >actual &&
1234        cat >expect <<-\EOF &&
1235        4:Subject: [PATCH] subject
1236        8:
1237        9:Signed-off-by: C O Mitter <committer@example.com>
1238        EOF
1239        test_cmp expect actual
1240'
1241
1242test_expect_success 'signoff: no existing signoffs' '
1243        append_signoff <<-\EOF >actual &&
1244        subject
1245
1246        body
1247        EOF
1248        cat >expect <<-\EOF &&
1249        4:Subject: [PATCH] subject
1250        8:
1251        10:
1252        11:Signed-off-by: C O Mitter <committer@example.com>
1253        EOF
1254        test_cmp expect actual
1255'
1256
1257test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1258        printf "subject\n\nbody" | append_signoff >actual &&
1259        cat >expect <<-\EOF &&
1260        4:Subject: [PATCH] subject
1261        8:
1262        10:
1263        11:Signed-off-by: C O Mitter <committer@example.com>
1264        EOF
1265        test_cmp expect actual
1266'
1267
1268test_expect_success 'signoff: some random signoff' '
1269        append_signoff <<-\EOF >actual &&
1270        subject
1271
1272        body
1273
1274        Signed-off-by: my@house
1275        EOF
1276        cat >expect <<-\EOF &&
1277        4:Subject: [PATCH] subject
1278        8:
1279        10:
1280        11:Signed-off-by: my@house
1281        12:Signed-off-by: C O Mitter <committer@example.com>
1282        EOF
1283        test_cmp expect actual
1284'
1285
1286test_expect_success 'signoff: misc conforming footer elements' '
1287        append_signoff <<-\EOF >actual &&
1288        subject
1289
1290        body
1291
1292        Signed-off-by: my@house
1293        (cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1294        Tested-by: Some One <someone@example.com>
1295        Bug: 1234
1296        EOF
1297        cat >expect <<-\EOF &&
1298        4:Subject: [PATCH] subject
1299        8:
1300        10:
1301        11:Signed-off-by: my@house
1302        15:Signed-off-by: C O Mitter <committer@example.com>
1303        EOF
1304        test_cmp expect actual
1305'
1306
1307test_expect_success 'signoff: some random signoff-alike' '
1308        append_signoff <<-\EOF >actual &&
1309        subject
1310
1311        body
1312        Fooled-by-me: my@house
1313        EOF
1314        cat >expect <<-\EOF &&
1315        4:Subject: [PATCH] subject
1316        8:
1317        11:
1318        12:Signed-off-by: C O Mitter <committer@example.com>
1319        EOF
1320        test_cmp expect actual
1321'
1322
1323test_expect_success 'signoff: not really a signoff' '
1324        append_signoff <<-\EOF >actual &&
1325        subject
1326
1327        I want to mention about Signed-off-by: here.
1328        EOF
1329        cat >expect <<-\EOF &&
1330        4:Subject: [PATCH] subject
1331        8:
1332        9:I want to mention about Signed-off-by: here.
1333        10:
1334        11:Signed-off-by: C O Mitter <committer@example.com>
1335        EOF
1336        test_cmp expect actual
1337'
1338
1339test_expect_success 'signoff: not really a signoff (2)' '
1340        append_signoff <<-\EOF >actual &&
1341        subject
1342
1343        My unfortunate
1344        Signed-off-by: example happens to be wrapped here.
1345        EOF
1346        cat >expect <<-\EOF &&
1347        4:Subject: [PATCH] subject
1348        8:
1349        10:Signed-off-by: example happens to be wrapped here.
1350        11:Signed-off-by: C O Mitter <committer@example.com>
1351        EOF
1352        test_cmp expect actual
1353'
1354
1355test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1356        append_signoff <<-\EOF >actual &&
1357        subject
1358
1359        Signed-off-by: my@house
1360        Signed-off-by: your@house
1361
1362        A lot of houses.
1363        EOF
1364        cat >expect <<-\EOF &&
1365        4:Subject: [PATCH] subject
1366        8:
1367        9:Signed-off-by: my@house
1368        10:Signed-off-by: your@house
1369        11:
1370        13:
1371        14:Signed-off-by: C O Mitter <committer@example.com>
1372        EOF
1373        test_cmp expect actual
1374'
1375
1376test_expect_success 'signoff: the same signoff at the end' '
1377        append_signoff <<-\EOF >actual &&
1378        subject
1379
1380        body
1381
1382        Signed-off-by: C O Mitter <committer@example.com>
1383        EOF
1384        cat >expect <<-\EOF &&
1385        4:Subject: [PATCH] subject
1386        8:
1387        10:
1388        11:Signed-off-by: C O Mitter <committer@example.com>
1389        EOF
1390        test_cmp expect actual
1391'
1392
1393test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1394        printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1395                append_signoff >actual &&
1396        cat >expect <<-\EOF &&
1397        4:Subject: [PATCH] subject
1398        8:
1399        9:Signed-off-by: C O Mitter <committer@example.com>
1400        EOF
1401        test_cmp expect actual
1402'
1403
1404test_expect_success 'signoff: the same signoff NOT at the end' '
1405        append_signoff <<-\EOF >actual &&
1406        subject
1407
1408        body
1409
1410        Signed-off-by: C O Mitter <committer@example.com>
1411        Signed-off-by: my@house
1412        EOF
1413        cat >expect <<-\EOF &&
1414        4:Subject: [PATCH] subject
1415        8:
1416        10:
1417        11:Signed-off-by: C O Mitter <committer@example.com>
1418        12:Signed-off-by: my@house
1419        EOF
1420        test_cmp expect actual
1421'
1422
1423test_expect_success 'signoff: tolerate garbage in conforming footer' '
1424        append_signoff <<-\EOF >actual &&
1425        subject
1426
1427        body
1428
1429        Tested-by: my@house
1430        Some Trash
1431        Signed-off-by: C O Mitter <committer@example.com>
1432        EOF
1433        cat >expect <<-\EOF &&
1434        4:Subject: [PATCH] subject
1435        8:
1436        10:
1437        13:Signed-off-by: C O Mitter <committer@example.com>
1438        EOF
1439        test_cmp expect actual
1440'
1441
1442test_expect_success 'signoff: respect trailer config' '
1443        append_signoff <<-\EOF >actual &&
1444        subject
1445
1446        Myfooter: x
1447        Some Trash
1448        EOF
1449        cat >expect <<-\EOF &&
1450        4:Subject: [PATCH] subject
1451        8:
1452        11:
1453        12:Signed-off-by: C O Mitter <committer@example.com>
1454        EOF
1455        test_cmp expect actual &&
1456
1457        test_config trailer.Myfooter.ifexists add &&
1458        append_signoff <<-\EOF >actual &&
1459        subject
1460
1461        Myfooter: x
1462        Some Trash
1463        EOF
1464        cat >expect <<-\EOF &&
1465        4:Subject: [PATCH] subject
1466        8:
1467        11:Signed-off-by: C O Mitter <committer@example.com>
1468        EOF
1469        test_cmp expect actual
1470'
1471
1472test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1473        append_signoff <<-\EOF >actual &&
1474        subject
1475
1476        body
1477
1478        Reviewed-id: Noone
1479        Tested-by: my@house
1480        Change-id: Ideadbeef
1481        Signed-off-by: C O Mitter <committer@example.com>
1482        Bug: 1234
1483        EOF
1484        cat >expect <<-\EOF &&
1485        4:Subject: [PATCH] subject
1486        8:
1487        10:
1488        14:Signed-off-by: C O Mitter <committer@example.com>
1489        EOF
1490        test_cmp expect actual
1491'
1492
1493test_expect_success 'format patch ignores color.ui' '
1494        test_unconfig color.ui &&
1495        git format-patch --stdout -1 >expect &&
1496        test_config color.ui always &&
1497        git format-patch --stdout -1 >actual &&
1498        test_cmp expect actual
1499'
1500
1501test_expect_success 'cover letter using branch description (1)' '
1502        git checkout rebuild-1 &&
1503        test_config branch.rebuild-1.description hello &&
1504        git format-patch --stdout --cover-letter master >actual &&
1505        grep hello actual >/dev/null
1506'
1507
1508test_expect_success 'cover letter using branch description (2)' '
1509        git checkout rebuild-1 &&
1510        test_config branch.rebuild-1.description hello &&
1511        git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1512        grep hello actual >/dev/null
1513'
1514
1515test_expect_success 'cover letter using branch description (3)' '
1516        git checkout rebuild-1 &&
1517        test_config branch.rebuild-1.description hello &&
1518        git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
1519        grep hello actual >/dev/null
1520'
1521
1522test_expect_success 'cover letter using branch description (4)' '
1523        git checkout rebuild-1 &&
1524        test_config branch.rebuild-1.description hello &&
1525        git format-patch --stdout --cover-letter master.. >actual &&
1526        grep hello actual >/dev/null
1527'
1528
1529test_expect_success 'cover letter using branch description (5)' '
1530        git checkout rebuild-1 &&
1531        test_config branch.rebuild-1.description hello &&
1532        git format-patch --stdout --cover-letter -2 HEAD >actual &&
1533        grep hello actual >/dev/null
1534'
1535
1536test_expect_success 'cover letter using branch description (6)' '
1537        git checkout rebuild-1 &&
1538        test_config branch.rebuild-1.description hello &&
1539        git format-patch --stdout --cover-letter -2 >actual &&
1540        grep hello actual >/dev/null
1541'
1542
1543test_expect_success 'cover letter with nothing' '
1544        git format-patch --stdout --cover-letter >actual &&
1545        test_line_count = 0 actual
1546'
1547
1548test_expect_success 'cover letter auto' '
1549        mkdir -p tmp &&
1550        test_when_finished "rm -rf tmp;
1551                git config --unset format.coverletter" &&
1552
1553        git config format.coverletter auto &&
1554        git format-patch -o tmp -1 >list &&
1555        test_line_count = 1 list &&
1556        git format-patch -o tmp -2 >list &&
1557        test_line_count = 3 list
1558'
1559
1560test_expect_success 'cover letter auto user override' '
1561        mkdir -p tmp &&
1562        test_when_finished "rm -rf tmp;
1563                git config --unset format.coverletter" &&
1564
1565        git config format.coverletter auto &&
1566        git format-patch -o tmp --cover-letter -1 >list &&
1567        test_line_count = 2 list &&
1568        git format-patch -o tmp --cover-letter -2 >list &&
1569        test_line_count = 3 list &&
1570        git format-patch -o tmp --no-cover-letter -1 >list &&
1571        test_line_count = 1 list &&
1572        git format-patch -o tmp --no-cover-letter -2 >list &&
1573        test_line_count = 2 list
1574'
1575
1576test_expect_success 'format-patch --zero-commit' '
1577        git format-patch --zero-commit --stdout v2..v1 >patch2 &&
1578        grep "^From " patch2 | sort | uniq >actual &&
1579        echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
1580        test_cmp expect actual
1581'
1582
1583test_expect_success 'From line has expected format' '
1584        git format-patch --stdout v2..v1 >patch2 &&
1585        grep "^From " patch2 >from &&
1586        grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
1587        test_cmp from filtered
1588'
1589
1590test_expect_success 'format-patch format.outputDirectory option' '
1591        test_config format.outputDirectory patches &&
1592        rm -fr patches &&
1593        git format-patch master..side &&
1594        test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l)
1595'
1596
1597test_expect_success 'format-patch -o overrides format.outputDirectory' '
1598        test_config format.outputDirectory patches &&
1599        rm -fr patches patchset &&
1600        git format-patch master..side -o patchset &&
1601        test_path_is_missing patches &&
1602        test_path_is_dir patchset
1603'
1604
1605test_expect_success 'format-patch --base' '
1606        git checkout patchid &&
1607        git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
1608        git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
1609        echo >expect &&
1610        echo "base-commit: $(git rev-parse HEAD~3)" >>expect &&
1611        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1612        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1613        signature >>expect &&
1614        test_cmp expect actual1 &&
1615        test_cmp expect actual2 &&
1616        echo >fail &&
1617        echo "base-commit: $(git rev-parse HEAD~3)" >>fail &&
1618        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1619        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1620        signature >>fail &&
1621        ! test_cmp fail actual1 &&
1622        ! test_cmp fail actual2
1623'
1624
1625test_expect_success 'format-patch --base errors out when base commit is in revision list' '
1626        test_must_fail git format-patch --base=HEAD -2 &&
1627        test_must_fail git format-patch --base=HEAD~1 -2 &&
1628        git format-patch --stdout --base=HEAD~2 -2 >patch &&
1629        grep "^base-commit:" patch >actual &&
1630        echo "base-commit: $(git rev-parse HEAD~2)" >expect &&
1631        test_cmp expect actual
1632'
1633
1634test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
1635        # For history as below:
1636        #
1637        #    ---Q---P---Z---Y---*---X
1638        #        \             /
1639        #         ------------W
1640        #
1641        # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
1642        git checkout -b topic1 master &&
1643        git rev-parse HEAD >commit-id-base &&
1644        test_commit P &&
1645        git rev-parse HEAD >commit-id-P &&
1646        test_commit Z &&
1647        git rev-parse HEAD >commit-id-Z &&
1648        test_commit Y &&
1649        git checkout -b topic2 master &&
1650        test_commit W &&
1651        git merge topic1 &&
1652        test_commit X &&
1653        test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
1654        test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
1655        git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
1656        grep "^base-commit:" patch >actual &&
1657        echo "base-commit: $(cat commit-id-base)" >expect &&
1658        test_cmp expect actual
1659'
1660
1661test_expect_success 'format-patch --base=auto' '
1662        git checkout -b upstream master &&
1663        git checkout -b local upstream &&
1664        git branch --set-upstream-to=upstream &&
1665        test_commit N1 &&
1666        test_commit N2 &&
1667        git format-patch --stdout --base=auto -2 >patch &&
1668        grep "^base-commit:" patch >actual &&
1669        echo "base-commit: $(git rev-parse upstream)" >expect &&
1670        test_cmp expect actual
1671'
1672
1673test_expect_success 'format-patch errors out when history involves criss-cross' '
1674        # setup criss-cross history
1675        #
1676        #   B---M1---D
1677        #  / \ /
1678        # A   X
1679        #  \ / \
1680        #   C---M2---E
1681        #
1682        git checkout master &&
1683        test_commit A &&
1684        git checkout -b xb master &&
1685        test_commit B &&
1686        git checkout -b xc master &&
1687        test_commit C &&
1688        git checkout -b xbc xb -- &&
1689        git merge xc &&
1690        git checkout -b xcb xc -- &&
1691        git branch --set-upstream-to=xbc &&
1692        git merge xb &&
1693        git checkout xbc &&
1694        test_commit D &&
1695        git checkout xcb &&
1696        test_commit E &&
1697        test_must_fail  git format-patch --base=auto -1
1698'
1699
1700test_expect_success 'format-patch format.useAutoBaseoption' '
1701        test_when_finished "git config --unset format.useAutoBase" &&
1702        git checkout local &&
1703        git config format.useAutoBase true &&
1704        git format-patch --stdout -1 >patch &&
1705        grep "^base-commit:" patch >actual &&
1706        echo "base-commit: $(git rev-parse upstream)" >expect &&
1707        test_cmp expect actual
1708'
1709
1710test_expect_success 'format-patch --base overrides format.useAutoBase' '
1711        test_when_finished "git config --unset format.useAutoBase" &&
1712        git config format.useAutoBase true &&
1713        git format-patch --stdout --base=HEAD~1 -1 >patch &&
1714        grep "^base-commit:" patch >actual &&
1715        echo "base-commit: $(git rev-parse HEAD~1)" >expect &&
1716        test_cmp expect actual
1717'
1718
1719test_expect_success 'format-patch --base with --attach' '
1720        git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
1721        sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
1722                patch >actual &&
1723        test_write_lines 1 2 >expect &&
1724        test_cmp expect actual
1725'
1726test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
1727        test_when_finished "rm -fr patches" &&
1728        git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
1729        ! egrep "^--+mimemime" patches/0000*.patch &&
1730        egrep "^--+mimemime$" patches/0001*.patch >output &&
1731        test_line_count = 2 output &&
1732        egrep "^--+mimemime--$" patches/0001*.patch >output &&
1733        test_line_count = 1 output
1734'
1735
1736test_expect_success 'format-patch --pretty=mboxrd' '
1737        sp=" " &&
1738        cat >msg <<-INPUT_END &&
1739        mboxrd should escape the body
1740
1741        From could trip up a loose mbox parser
1742        >From extra escape for reversibility
1743        >>From extra escape for reversibility 2
1744        from lower case not escaped
1745        Fromm bad speling not escaped
1746         From with leading space not escaped
1747
1748        F
1749        From
1750        From$sp
1751        From    $sp
1752        From    $sp
1753        INPUT_END
1754
1755        cat >expect <<-INPUT_END &&
1756        >From could trip up a loose mbox parser
1757        >>From extra escape for reversibility
1758        >>>From extra escape for reversibility 2
1759        from lower case not escaped
1760        Fromm bad speling not escaped
1761         From with leading space not escaped
1762
1763        F
1764        From
1765        From
1766        From
1767        From
1768        INPUT_END
1769
1770        C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
1771        git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
1772        git grep -h --no-index -A11 \
1773                "^>From could trip up a loose mbox parser" patch >actual &&
1774        test_cmp expect actual
1775'
1776
1777test_expect_success 'interdiff: setup' '
1778        git checkout -b boop master &&
1779        test_commit fnorp blorp &&
1780        test_commit fleep blorp
1781'
1782
1783test_expect_success 'interdiff: cover-letter' '
1784        sed "y/q/ /" >expect <<-\EOF &&
1785        +fleep
1786        --q
1787        EOF
1788        git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1789        test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1790        test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
1791        sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1792        test_cmp expect actual
1793'
1794
1795test_expect_success 'interdiff: reroll-count' '
1796        git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
1797        test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
1798'
1799
1800test_expect_success 'interdiff: solo-patch' '
1801        cat >expect <<-\EOF &&
1802          +fleep
1803
1804        EOF
1805        git format-patch --interdiff=boop~2 -1 boop &&
1806        test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
1807        sed "1,/^  @@ /d; /^$/q" <0001-fleep.patch >actual &&
1808        test_cmp expect actual
1809'
1810
1811test_done