62f5680f057a2dd14eeb0ccf27abba4d33ea7995
   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
 795test_expect_success 'format-patch --numstat should produce a patch' '
 796        git format-patch --numstat --stdout master..side > output &&
 797        test 5 = $(grep "^diff --git a/" output | wc -l)'
 798
 799test_expect_success 'format-patch -- <path>' '
 800        git format-patch master..side -- file 2>error &&
 801        ! grep "Use .--" error
 802'
 803
 804test_expect_success 'format-patch --ignore-if-in-upstream HEAD' '
 805        git format-patch --ignore-if-in-upstream HEAD
 806'
 807
 808git_version="$(git --version | sed "s/.* //")"
 809
 810signature() {
 811        printf "%s\n%s\n\n" "-- " "${1:-$git_version}"
 812}
 813
 814test_expect_success 'format-patch default signature' '
 815        git format-patch --stdout -1 | tail -n 3 >output &&
 816        signature >expect &&
 817        test_cmp expect output
 818'
 819
 820test_expect_success 'format-patch --signature' '
 821        git format-patch --stdout --signature="my sig" -1 | tail -n 3 >output &&
 822        signature "my sig" >expect &&
 823        test_cmp expect output
 824'
 825
 826test_expect_success 'format-patch with format.signature config' '
 827        git config format.signature "config sig" &&
 828        git format-patch --stdout -1 >output &&
 829        grep "config sig" output
 830'
 831
 832test_expect_success 'format-patch --signature overrides format.signature' '
 833        git config format.signature "config sig" &&
 834        git format-patch --stdout --signature="overrides" -1 >output &&
 835        ! grep "config sig" output &&
 836        grep "overrides" output
 837'
 838
 839test_expect_success 'format-patch --no-signature ignores format.signature' '
 840        git config format.signature "config sig" &&
 841        git format-patch --stdout --signature="my sig" --no-signature \
 842                -1 >output &&
 843        check_patch output &&
 844        ! grep "config sig" output &&
 845        ! grep "my sig" output &&
 846        ! grep "^-- \$" output
 847'
 848
 849test_expect_success 'format-patch --signature --cover-letter' '
 850        git config --unset-all format.signature &&
 851        git format-patch --stdout --signature="my sig" --cover-letter \
 852                -1 >output &&
 853        grep "my sig" output &&
 854        test 2 = $(grep "my sig" output | wc -l)
 855'
 856
 857test_expect_success 'format.signature="" suppresses signatures' '
 858        git config format.signature "" &&
 859        git format-patch --stdout -1 >output &&
 860        check_patch output &&
 861        ! grep "^-- \$" output
 862'
 863
 864test_expect_success 'format-patch --no-signature suppresses signatures' '
 865        git config --unset-all format.signature &&
 866        git format-patch --stdout --no-signature -1 >output &&
 867        check_patch output &&
 868        ! grep "^-- \$" output
 869'
 870
 871test_expect_success 'format-patch --signature="" suppresses signatures' '
 872        git format-patch --stdout --signature="" -1 >output &&
 873        check_patch output &&
 874        ! grep "^-- \$" output
 875'
 876
 877test_expect_success 'prepare mail-signature input' '
 878        cat >mail-signature <<-\EOF
 879
 880        Test User <test.email@kernel.org>
 881        http://git.kernel.org/cgit/git/git.git
 882
 883        git.kernel.org/?p=git/git.git;a=summary
 884
 885        EOF
 886'
 887
 888test_expect_success '--signature-file=file works' '
 889        git format-patch --stdout --signature-file=mail-signature -1 >output &&
 890        check_patch output &&
 891        sed -e "1,/^-- \$/d" <output >actual &&
 892        {
 893                cat mail-signature && echo
 894        } >expect &&
 895        test_cmp expect actual
 896'
 897
 898test_expect_success 'format.signaturefile works' '
 899        test_config format.signaturefile mail-signature &&
 900        git format-patch --stdout -1 >output &&
 901        check_patch output &&
 902        sed -e "1,/^-- \$/d" <output >actual &&
 903        {
 904                cat mail-signature && echo
 905        } >expect &&
 906        test_cmp expect actual
 907'
 908
 909test_expect_success '--no-signature suppresses format.signaturefile ' '
 910        test_config format.signaturefile mail-signature &&
 911        git format-patch --stdout --no-signature -1 >output &&
 912        check_patch output &&
 913        ! grep "^-- \$" output
 914'
 915
 916test_expect_success '--signature-file overrides format.signaturefile' '
 917        cat >other-mail-signature <<-\EOF &&
 918        Use this other signature instead of mail-signature.
 919        EOF
 920        test_config format.signaturefile mail-signature &&
 921        git format-patch --stdout \
 922                        --signature-file=other-mail-signature -1 >output &&
 923        check_patch output &&
 924        sed -e "1,/^-- \$/d" <output >actual &&
 925        {
 926                cat other-mail-signature && echo
 927        } >expect &&
 928        test_cmp expect actual
 929'
 930
 931test_expect_success '--signature overrides format.signaturefile' '
 932        test_config format.signaturefile mail-signature &&
 933        git format-patch --stdout --signature="my sig" -1 >output &&
 934        check_patch output &&
 935        grep "my sig" output
 936'
 937
 938test_expect_success TTY 'format-patch --stdout paginates' '
 939        rm -f pager_used &&
 940        test_terminal env GIT_PAGER="wc >pager_used" git format-patch --stdout --all &&
 941        test_path_is_file pager_used
 942'
 943
 944 test_expect_success TTY 'format-patch --stdout pagination can be disabled' '
 945        rm -f pager_used &&
 946        test_terminal env GIT_PAGER="wc >pager_used" git --no-pager format-patch --stdout --all &&
 947        test_terminal env GIT_PAGER="wc >pager_used" git -c "pager.format-patch=false" format-patch --stdout --all &&
 948        test_path_is_missing pager_used &&
 949        test_path_is_missing .git/pager_used
 950'
 951
 952test_expect_success 'format-patch handles multi-line subjects' '
 953        rm -rf patches/ &&
 954        echo content >>file &&
 955        for i in one two three; do echo $i; done >msg &&
 956        git add file &&
 957        git commit -F msg &&
 958        git format-patch -o patches -1 &&
 959        grep ^Subject: patches/0001-one.patch >actual &&
 960        echo "Subject: [PATCH] one two three" >expect &&
 961        test_cmp expect actual
 962'
 963
 964test_expect_success 'format-patch handles multi-line encoded subjects' '
 965        rm -rf patches/ &&
 966        echo content >>file &&
 967        for i in en två tre; do echo $i; done >msg &&
 968        git add file &&
 969        git commit -F msg &&
 970        git format-patch -o patches -1 &&
 971        grep ^Subject: patches/0001-en.patch >actual &&
 972        echo "Subject: [PATCH] =?UTF-8?q?en=20tv=C3=A5=20tre?=" >expect &&
 973        test_cmp expect actual
 974'
 975
 976M8="foo bar "
 977M64=$M8$M8$M8$M8$M8$M8$M8$M8
 978M512=$M64$M64$M64$M64$M64$M64$M64$M64
 979cat >expect <<'EOF'
 980Subject: [PATCH] foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo
 981 bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar foo bar
 982 foo bar foo bar 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
 987EOF
 988test_expect_success 'format-patch wraps extremely long subject (ascii)' '
 989        echo content >>file &&
 990        git add file &&
 991        git commit -m "$M512" &&
 992        git format-patch --stdout -1 >patch &&
 993        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
 994        test_cmp expect subject
 995'
 996
 997M8="föö bar "
 998M64=$M8$M8$M8$M8$M8$M8$M8$M8
 999M512=$M64$M64$M64$M64$M64$M64$M64$M64
1000cat >expect <<'EOF'
1001Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1002 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1003 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1004 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1005 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1006 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1007 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1008 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1009 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1010 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1011 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1012 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1013 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1014 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1015 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1016 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1017 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1018 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1019 =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?=
1020 =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?=
1021 =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?=
1022 =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?=
1023 =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?=
1024 =?UTF-8?q?bar?=
1025EOF
1026test_expect_success 'format-patch wraps extremely long subject (rfc2047)' '
1027        rm -rf patches/ &&
1028        echo content >>file &&
1029        git add file &&
1030        git commit -m "$M512" &&
1031        git format-patch --stdout -1 >patch &&
1032        sed -n "/^Subject/p; /^ /p; /^$/q" <patch >subject &&
1033        test_cmp expect subject
1034'
1035
1036check_author() {
1037        echo content >>file &&
1038        git add file &&
1039        GIT_AUTHOR_NAME=$1 git commit -m author-check &&
1040        git format-patch --stdout -1 >patch &&
1041        sed -n "/^From: /p; /^ /p; /^$/q" <patch >actual &&
1042        test_cmp expect actual
1043}
1044
1045cat >expect <<'EOF'
1046From: "Foo B. Bar" <author@example.com>
1047EOF
1048test_expect_success 'format-patch quotes dot in from-headers' '
1049        check_author "Foo B. Bar"
1050'
1051
1052cat >expect <<'EOF'
1053From: "Foo \"The Baz\" Bar" <author@example.com>
1054EOF
1055test_expect_success 'format-patch quotes double-quote in from-headers' '
1056        check_author "Foo \"The Baz\" Bar"
1057'
1058
1059cat >expect <<'EOF'
1060From: =?UTF-8?q?F=C3=B6o=20Bar?= <author@example.com>
1061EOF
1062test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' '
1063        check_author "Föo Bar"
1064'
1065
1066cat >expect <<'EOF'
1067From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= <author@example.com>
1068EOF
1069test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' '
1070        check_author "Föo B. Bar"
1071'
1072
1073cat >expect <<EOF
1074From: foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_
1075 <author@example.com>
1076EOF
1077test_expect_success 'format-patch wraps moderately long from-header (ascii)' '
1078        check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_"
1079'
1080
1081cat >expect <<'EOF'
1082From: Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1083 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1084 Bar Foo Bar Foo Bar Foo Bar <author@example.com>
1085EOF
1086test_expect_success 'format-patch wraps extremely long from-header (ascii)' '
1087        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"
1088'
1089
1090cat >expect <<'EOF'
1091From: "Foo.Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
1092 Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
1093 Bar Foo Bar Foo Bar Foo Bar" <author@example.com>
1094EOF
1095test_expect_success 'format-patch wraps extremely long from-header (rfc822)' '
1096        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"
1097'
1098
1099cat >expect <<'EOF'
1100From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?=
1101 =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?=
1102 =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?=
1103 =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?=
1104 =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= <author@example.com>
1105EOF
1106test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
1107        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"
1108'
1109
1110cat >expect <<'EOF'
1111Subject: header with . in it
1112EOF
1113test_expect_success 'subject lines do not have 822 atom-quoting' '
1114        echo content >>file &&
1115        git add file &&
1116        git commit -m "header with . in it" &&
1117        git format-patch -k -1 --stdout >patch &&
1118        grep ^Subject: patch >actual &&
1119        test_cmp expect actual
1120'
1121
1122cat >expect <<'EOF'
1123Subject: [PREFIX 1/1] header with . in it
1124EOF
1125test_expect_success 'subject prefixes have space prepended' '
1126        git format-patch -n -1 --stdout --subject-prefix=PREFIX >patch &&
1127        grep ^Subject: patch >actual &&
1128        test_cmp expect actual
1129'
1130
1131cat >expect <<'EOF'
1132Subject: [1/1] header with . in it
1133EOF
1134test_expect_success 'empty subject prefix does not have extra space' '
1135        git format-patch -n -1 --stdout --subject-prefix= >patch &&
1136        grep ^Subject: patch >actual &&
1137        test_cmp expect actual
1138'
1139
1140test_expect_success '--rfc' '
1141        cat >expect <<-\EOF &&
1142        Subject: [RFC PATCH 1/1] header with . in it
1143        EOF
1144        git format-patch -n -1 --stdout --rfc >patch &&
1145        grep ^Subject: patch >actual &&
1146        test_cmp expect actual
1147'
1148
1149test_expect_success '--from=ident notices bogus ident' '
1150        test_must_fail git format-patch -1 --stdout --from=foo >patch
1151'
1152
1153test_expect_success '--from=ident replaces author' '
1154        git format-patch -1 --stdout --from="Me <me@example.com>" >patch &&
1155        cat >expect <<-\EOF &&
1156        From: Me <me@example.com>
1157
1158        From: A U Thor <author@example.com>
1159
1160        EOF
1161        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1162        test_cmp expect patch.head
1163'
1164
1165test_expect_success '--from uses committer ident' '
1166        git format-patch -1 --stdout --from >patch &&
1167        cat >expect <<-\EOF &&
1168        From: C O Mitter <committer@example.com>
1169
1170        From: A U Thor <author@example.com>
1171
1172        EOF
1173        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1174        test_cmp expect patch.head
1175'
1176
1177test_expect_success '--from omits redundant in-body header' '
1178        git format-patch -1 --stdout --from="A U Thor <author@example.com>" >patch &&
1179        cat >expect <<-\EOF &&
1180        From: A U Thor <author@example.com>
1181
1182        EOF
1183        sed -ne "/^From:/p; /^$/p; /^---$/q" <patch >patch.head &&
1184        test_cmp expect patch.head
1185'
1186
1187test_expect_success 'in-body headers trigger content encoding' '
1188        test_env GIT_AUTHOR_NAME="éxötìc" test_commit exotic &&
1189        test_when_finished "git reset --hard HEAD^" &&
1190        git format-patch -1 --stdout --from >patch &&
1191        cat >expect <<-\EOF &&
1192        From: C O Mitter <committer@example.com>
1193        Content-Type: text/plain; charset=UTF-8
1194
1195        From: éxötìc <author@example.com>
1196
1197        EOF
1198        sed -ne "/^From:/p; /^$/p; /^Content-Type/p; /^---$/q" <patch >patch.head &&
1199        test_cmp expect patch.head
1200'
1201
1202append_signoff()
1203{
1204        C=$(git commit-tree HEAD^^{tree} -p HEAD) &&
1205        git format-patch --stdout --signoff $C^..$C >append_signoff.patch &&
1206        sed -n -e "1,/^---$/p" append_signoff.patch |
1207                egrep -n "^Subject|Sign|^$"
1208}
1209
1210test_expect_success 'signoff: commit with no body' '
1211        append_signoff </dev/null >actual &&
1212        cat <<\EOF | sed "s/EOL$//" >expect &&
12134:Subject: [PATCH] EOL
12148:
12159:Signed-off-by: C O Mitter <committer@example.com>
1216EOF
1217        test_cmp expect actual
1218'
1219
1220test_expect_success 'signoff: commit with only subject' '
1221        echo subject | append_signoff >actual &&
1222        cat >expect <<\EOF &&
12234:Subject: [PATCH] subject
12248:
12259:Signed-off-by: C O Mitter <committer@example.com>
1226EOF
1227        test_cmp expect actual
1228'
1229
1230test_expect_success 'signoff: commit with only subject that does not end with NL' '
1231        printf subject | append_signoff >actual &&
1232        cat >expect <<\EOF &&
12334:Subject: [PATCH] subject
12348:
12359:Signed-off-by: C O Mitter <committer@example.com>
1236EOF
1237        test_cmp expect actual
1238'
1239
1240test_expect_success 'signoff: no existing signoffs' '
1241        append_signoff <<\EOF >actual &&
1242subject
1243
1244body
1245EOF
1246        cat >expect <<\EOF &&
12474:Subject: [PATCH] subject
12488:
124910:
125011:Signed-off-by: C O Mitter <committer@example.com>
1251EOF
1252        test_cmp expect actual
1253'
1254
1255test_expect_success 'signoff: no existing signoffs and no trailing NL' '
1256        printf "subject\n\nbody" | append_signoff >actual &&
1257        cat >expect <<\EOF &&
12584:Subject: [PATCH] subject
12598:
126010:
126111:Signed-off-by: C O Mitter <committer@example.com>
1262EOF
1263        test_cmp expect actual
1264'
1265
1266test_expect_success 'signoff: some random signoff' '
1267        append_signoff <<\EOF >actual &&
1268subject
1269
1270body
1271
1272Signed-off-by: my@house
1273EOF
1274        cat >expect <<\EOF &&
12754:Subject: [PATCH] subject
12768:
127710:
127811:Signed-off-by: my@house
127912:Signed-off-by: C O Mitter <committer@example.com>
1280EOF
1281        test_cmp expect actual
1282'
1283
1284test_expect_success 'signoff: misc conforming footer elements' '
1285        append_signoff <<\EOF >actual &&
1286subject
1287
1288body
1289
1290Signed-off-by: my@house
1291(cherry picked from commit da39a3ee5e6b4b0d3255bfef95601890afd80709)
1292Tested-by: Some One <someone@example.com>
1293Bug: 1234
1294EOF
1295        cat >expect <<\EOF &&
12964:Subject: [PATCH] subject
12978:
129810:
129911:Signed-off-by: my@house
130015:Signed-off-by: C O Mitter <committer@example.com>
1301EOF
1302        test_cmp expect actual
1303'
1304
1305test_expect_success 'signoff: some random signoff-alike' '
1306        append_signoff <<\EOF >actual &&
1307subject
1308
1309body
1310Fooled-by-me: my@house
1311EOF
1312        cat >expect <<\EOF &&
13134:Subject: [PATCH] subject
13148:
131511:
131612:Signed-off-by: C O Mitter <committer@example.com>
1317EOF
1318        test_cmp expect actual
1319'
1320
1321test_expect_success 'signoff: not really a signoff' '
1322        append_signoff <<\EOF >actual &&
1323subject
1324
1325I want to mention about Signed-off-by: here.
1326EOF
1327        cat >expect <<\EOF &&
13284:Subject: [PATCH] subject
13298:
13309:I want to mention about Signed-off-by: here.
133110:
133211:Signed-off-by: C O Mitter <committer@example.com>
1333EOF
1334        test_cmp expect actual
1335'
1336
1337test_expect_success 'signoff: not really a signoff (2)' '
1338        append_signoff <<\EOF >actual &&
1339subject
1340
1341My unfortunate
1342Signed-off-by: example happens to be wrapped here.
1343EOF
1344        cat >expect <<\EOF &&
13454:Subject: [PATCH] subject
13468:
134710:Signed-off-by: example happens to be wrapped here.
134811:Signed-off-by: C O Mitter <committer@example.com>
1349EOF
1350        test_cmp expect actual
1351'
1352
1353test_expect_success 'signoff: valid S-o-b paragraph in the middle' '
1354        append_signoff <<\EOF >actual &&
1355subject
1356
1357Signed-off-by: my@house
1358Signed-off-by: your@house
1359
1360A lot of houses.
1361EOF
1362        cat >expect <<\EOF &&
13634:Subject: [PATCH] subject
13648:
13659:Signed-off-by: my@house
136610:Signed-off-by: your@house
136711:
136813:
136914:Signed-off-by: C O Mitter <committer@example.com>
1370EOF
1371        test_cmp expect actual
1372'
1373
1374test_expect_success 'signoff: the same signoff at the end' '
1375        append_signoff <<\EOF >actual &&
1376subject
1377
1378body
1379
1380Signed-off-by: C O Mitter <committer@example.com>
1381EOF
1382        cat >expect <<\EOF &&
13834:Subject: [PATCH] subject
13848:
138510:
138611:Signed-off-by: C O Mitter <committer@example.com>
1387EOF
1388        test_cmp expect actual
1389'
1390
1391test_expect_success 'signoff: the same signoff at the end, no trailing NL' '
1392        printf "subject\n\nSigned-off-by: C O Mitter <committer@example.com>" |
1393                append_signoff >actual &&
1394        cat >expect <<\EOF &&
13954:Subject: [PATCH] subject
13968:
13979:Signed-off-by: C O Mitter <committer@example.com>
1398EOF
1399        test_cmp expect actual
1400'
1401
1402test_expect_success 'signoff: the same signoff NOT at the end' '
1403        append_signoff <<\EOF >actual &&
1404subject
1405
1406body
1407
1408Signed-off-by: C O Mitter <committer@example.com>
1409Signed-off-by: my@house
1410EOF
1411        cat >expect <<\EOF &&
14124:Subject: [PATCH] subject
14138:
141410:
141511:Signed-off-by: C O Mitter <committer@example.com>
141612:Signed-off-by: my@house
1417EOF
1418        test_cmp expect actual
1419'
1420
1421test_expect_success 'signoff: tolerate garbage in conforming footer' '
1422        append_signoff <<\EOF >actual &&
1423subject
1424
1425body
1426
1427Tested-by: my@house
1428Some Trash
1429Signed-off-by: C O Mitter <committer@example.com>
1430EOF
1431        cat >expect <<\EOF &&
14324:Subject: [PATCH] subject
14338:
143410:
143513:Signed-off-by: C O Mitter <committer@example.com>
1436EOF
1437        test_cmp expect actual
1438'
1439
1440test_expect_success 'signoff: respect trailer config' '
1441        append_signoff <<\EOF >actual &&
1442subject
1443
1444Myfooter: x
1445Some Trash
1446EOF
1447        cat >expect <<\EOF &&
14484:Subject: [PATCH] subject
14498:
145011:
145112:Signed-off-by: C O Mitter <committer@example.com>
1452EOF
1453        test_cmp expect actual &&
1454
1455        test_config trailer.Myfooter.ifexists add &&
1456        append_signoff <<\EOF >actual &&
1457subject
1458
1459Myfooter: x
1460Some Trash
1461EOF
1462        cat >expect <<\EOF &&
14634:Subject: [PATCH] subject
14648:
146511:Signed-off-by: C O Mitter <committer@example.com>
1466EOF
1467        test_cmp expect actual
1468'
1469
1470test_expect_success 'signoff: footer begins with non-signoff without @ sign' '
1471        append_signoff <<\EOF >actual &&
1472subject
1473
1474body
1475
1476Reviewed-id: Noone
1477Tested-by: my@house
1478Change-id: Ideadbeef
1479Signed-off-by: C O Mitter <committer@example.com>
1480Bug: 1234
1481EOF
1482        cat >expect <<\EOF &&
14834:Subject: [PATCH] subject
14848:
148510:
148614:Signed-off-by: C O Mitter <committer@example.com>
1487EOF
1488        test_cmp expect actual
1489'
1490
1491test_expect_success 'format patch ignores color.ui' '
1492        test_unconfig color.ui &&
1493        git format-patch --stdout -1 >expect &&
1494        test_config color.ui always &&
1495        git format-patch --stdout -1 >actual &&
1496        test_cmp expect actual
1497'
1498
1499test_expect_success 'cover letter using branch description (1)' '
1500        git checkout rebuild-1 &&
1501        test_config branch.rebuild-1.description hello &&
1502        git format-patch --stdout --cover-letter master >actual &&
1503        grep hello actual >/dev/null
1504'
1505
1506test_expect_success 'cover letter using branch description (2)' '
1507        git checkout rebuild-1 &&
1508        test_config branch.rebuild-1.description hello &&
1509        git format-patch --stdout --cover-letter rebuild-1~2..rebuild-1 >actual &&
1510        grep hello actual >/dev/null
1511'
1512
1513test_expect_success 'cover letter using branch description (3)' '
1514        git checkout rebuild-1 &&
1515        test_config branch.rebuild-1.description hello &&
1516        git format-patch --stdout --cover-letter ^master rebuild-1 >actual &&
1517        grep hello actual >/dev/null
1518'
1519
1520test_expect_success 'cover letter using branch description (4)' '
1521        git checkout rebuild-1 &&
1522        test_config branch.rebuild-1.description hello &&
1523        git format-patch --stdout --cover-letter master.. >actual &&
1524        grep hello actual >/dev/null
1525'
1526
1527test_expect_success 'cover letter using branch description (5)' '
1528        git checkout rebuild-1 &&
1529        test_config branch.rebuild-1.description hello &&
1530        git format-patch --stdout --cover-letter -2 HEAD >actual &&
1531        grep hello actual >/dev/null
1532'
1533
1534test_expect_success 'cover letter using branch description (6)' '
1535        git checkout rebuild-1 &&
1536        test_config branch.rebuild-1.description hello &&
1537        git format-patch --stdout --cover-letter -2 >actual &&
1538        grep hello actual >/dev/null
1539'
1540
1541test_expect_success 'cover letter with nothing' '
1542        git format-patch --stdout --cover-letter >actual &&
1543        test_line_count = 0 actual
1544'
1545
1546test_expect_success 'cover letter auto' '
1547        mkdir -p tmp &&
1548        test_when_finished "rm -rf tmp;
1549                git config --unset format.coverletter" &&
1550
1551        git config format.coverletter auto &&
1552        git format-patch -o tmp -1 >list &&
1553        test_line_count = 1 list &&
1554        git format-patch -o tmp -2 >list &&
1555        test_line_count = 3 list
1556'
1557
1558test_expect_success 'cover letter auto user override' '
1559        mkdir -p tmp &&
1560        test_when_finished "rm -rf tmp;
1561                git config --unset format.coverletter" &&
1562
1563        git config format.coverletter auto &&
1564        git format-patch -o tmp --cover-letter -1 >list &&
1565        test_line_count = 2 list &&
1566        git format-patch -o tmp --cover-letter -2 >list &&
1567        test_line_count = 3 list &&
1568        git format-patch -o tmp --no-cover-letter -1 >list &&
1569        test_line_count = 1 list &&
1570        git format-patch -o tmp --no-cover-letter -2 >list &&
1571        test_line_count = 2 list
1572'
1573
1574test_expect_success 'format-patch --zero-commit' '
1575        git format-patch --zero-commit --stdout v2..v1 >patch2 &&
1576        grep "^From " patch2 | sort | uniq >actual &&
1577        echo "From $ZERO_OID Mon Sep 17 00:00:00 2001" >expect &&
1578        test_cmp expect actual
1579'
1580
1581test_expect_success 'From line has expected format' '
1582        git format-patch --stdout v2..v1 >patch2 &&
1583        grep "^From " patch2 >from &&
1584        grep "^From $OID_REGEX Mon Sep 17 00:00:00 2001$" patch2 >filtered &&
1585        test_cmp from filtered
1586'
1587
1588test_expect_success 'format-patch format.outputDirectory option' '
1589        test_config format.outputDirectory patches &&
1590        rm -fr patches &&
1591        git format-patch master..side &&
1592        test $(git rev-list master..side | wc -l) -eq $(ls patches | wc -l)
1593'
1594
1595test_expect_success 'format-patch -o overrides format.outputDirectory' '
1596        test_config format.outputDirectory patches &&
1597        rm -fr patches patchset &&
1598        git format-patch master..side -o patchset &&
1599        test_path_is_missing patches &&
1600        test_path_is_dir patchset
1601'
1602
1603test_expect_success 'format-patch --base' '
1604        git checkout patchid &&
1605        git format-patch --stdout --base=HEAD~3 -1 | tail -n 7 >actual1 &&
1606        git format-patch --stdout --base=HEAD~3 HEAD~.. | tail -n 7 >actual2 &&
1607        echo >expect &&
1608        echo "base-commit: $(git rev-parse HEAD~3)" >>expect &&
1609        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1610        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --stable | awk "{print \$1}")" >>expect &&
1611        signature >> expect &&
1612        test_cmp expect actual1 &&
1613        test_cmp expect actual2 &&
1614        echo >fail &&
1615        echo "base-commit: $(git rev-parse HEAD~3)" >>fail &&
1616        echo "prerequisite-patch-id: $(git show --patch HEAD~2 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1617        echo "prerequisite-patch-id: $(git show --patch HEAD~1 | git patch-id --unstable | awk "{print \$1}")" >>fail &&
1618        signature >> fail &&
1619        ! test_cmp fail actual1 &&
1620        ! test_cmp fail actual2
1621'
1622
1623test_expect_success 'format-patch --base errors out when base commit is in revision list' '
1624        test_must_fail git format-patch --base=HEAD -2 &&
1625        test_must_fail git format-patch --base=HEAD~1 -2 &&
1626        git format-patch --stdout --base=HEAD~2 -2 >patch &&
1627        grep "^base-commit:" patch >actual &&
1628        echo "base-commit: $(git rev-parse HEAD~2)" >expect &&
1629        test_cmp expect actual
1630'
1631
1632test_expect_success 'format-patch --base errors out when base commit is not ancestor of revision list' '
1633        # For history as below:
1634        #
1635        #    ---Q---P---Z---Y---*---X
1636        #        \             /
1637        #         ------------W
1638        #
1639        # If "format-patch Z..X" is given, P and Z can not be specified as the base commit
1640        git checkout -b topic1 master &&
1641        git rev-parse HEAD >commit-id-base &&
1642        test_commit P &&
1643        git rev-parse HEAD >commit-id-P &&
1644        test_commit Z &&
1645        git rev-parse HEAD >commit-id-Z &&
1646        test_commit Y &&
1647        git checkout -b topic2 master &&
1648        test_commit W &&
1649        git merge topic1 &&
1650        test_commit X &&
1651        test_must_fail git format-patch --base=$(cat commit-id-P) -3 &&
1652        test_must_fail git format-patch --base=$(cat commit-id-Z) -3 &&
1653        git format-patch --stdout --base=$(cat commit-id-base) -3 >patch &&
1654        grep "^base-commit:" patch >actual &&
1655        echo "base-commit: $(cat commit-id-base)" >expect &&
1656        test_cmp expect actual
1657'
1658
1659test_expect_success 'format-patch --base=auto' '
1660        git checkout -b upstream master &&
1661        git checkout -b local upstream &&
1662        git branch --set-upstream-to=upstream &&
1663        test_commit N1 &&
1664        test_commit N2 &&
1665        git format-patch --stdout --base=auto -2 >patch &&
1666        grep "^base-commit:" patch >actual &&
1667        echo "base-commit: $(git rev-parse upstream)" >expect &&
1668        test_cmp expect actual
1669'
1670
1671test_expect_success 'format-patch errors out when history involves criss-cross' '
1672        # setup criss-cross history
1673        #
1674        #   B---M1---D
1675        #  / \ /
1676        # A   X
1677        #  \ / \
1678        #   C---M2---E
1679        #
1680        git checkout master &&
1681        test_commit A &&
1682        git checkout -b xb master &&
1683        test_commit B &&
1684        git checkout -b xc master &&
1685        test_commit C &&
1686        git checkout -b xbc xb -- &&
1687        git merge xc &&
1688        git checkout -b xcb xc -- &&
1689        git branch --set-upstream-to=xbc &&
1690        git merge xb &&
1691        git checkout xbc &&
1692        test_commit D &&
1693        git checkout xcb &&
1694        test_commit E &&
1695        test_must_fail  git format-patch --base=auto -1
1696'
1697
1698test_expect_success 'format-patch format.useAutoBaseoption' '
1699        test_when_finished "git config --unset format.useAutoBase" &&
1700        git checkout local &&
1701        git config format.useAutoBase true &&
1702        git format-patch --stdout -1 >patch &&
1703        grep "^base-commit:" patch >actual &&
1704        echo "base-commit: $(git rev-parse upstream)" >expect &&
1705        test_cmp expect actual
1706'
1707
1708test_expect_success 'format-patch --base overrides format.useAutoBase' '
1709        test_when_finished "git config --unset format.useAutoBase" &&
1710        git config format.useAutoBase true &&
1711        git format-patch --stdout --base=HEAD~1 -1 >patch &&
1712        grep "^base-commit:" patch >actual &&
1713        echo "base-commit: $(git rev-parse HEAD~1)" >expect &&
1714        test_cmp expect actual
1715'
1716
1717test_expect_success 'format-patch --base with --attach' '
1718        git format-patch --attach=mimemime --stdout --base=HEAD~ -1 >patch &&
1719        sed -n -e "/^base-commit:/s/.*/1/p" -e "/^---*mimemime--$/s/.*/2/p" \
1720                patch >actual &&
1721        test_write_lines 1 2 >expect &&
1722        test_cmp expect actual
1723'
1724test_expect_success 'format-patch --attach cover-letter only is non-multipart' '
1725        test_when_finished "rm -fr patches" &&
1726        git format-patch -o patches --cover-letter --attach=mimemime --base=HEAD~ -1 &&
1727        ! egrep "^--+mimemime" patches/0000*.patch &&
1728        egrep "^--+mimemime$" patches/0001*.patch >output &&
1729        test_line_count = 2 output &&
1730        egrep "^--+mimemime--$" patches/0001*.patch >output &&
1731        test_line_count = 1 output
1732'
1733
1734test_expect_success 'format-patch --pretty=mboxrd' '
1735        sp=" " &&
1736        cat >msg <<-INPUT_END &&
1737        mboxrd should escape the body
1738
1739        From could trip up a loose mbox parser
1740        >From extra escape for reversibility
1741        >>From extra escape for reversibility 2
1742        from lower case not escaped
1743        Fromm bad speling not escaped
1744         From with leading space not escaped
1745
1746        F
1747        From
1748        From$sp
1749        From    $sp
1750        From    $sp
1751        INPUT_END
1752
1753        cat >expect <<-INPUT_END &&
1754        >From could trip up a loose mbox parser
1755        >>From extra escape for reversibility
1756        >>>From extra escape for reversibility 2
1757        from lower case not escaped
1758        Fromm bad speling not escaped
1759         From with leading space not escaped
1760
1761        F
1762        From
1763        From
1764        From
1765        From
1766        INPUT_END
1767
1768        C=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&
1769        git format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&
1770        git grep -h --no-index -A11 \
1771                "^>From could trip up a loose mbox parser" patch >actual &&
1772        test_cmp expect actual
1773'
1774
1775test_expect_success 'interdiff: setup' '
1776        git checkout -b boop master &&
1777        test_commit fnorp blorp &&
1778        test_commit fleep blorp
1779'
1780
1781test_expect_success 'interdiff: cover-letter' '
1782        sed "y/q/ /" >expect <<-\EOF &&
1783        +fleep
1784        --q
1785        EOF
1786        git format-patch --cover-letter --interdiff=boop~2 -1 boop &&
1787        test_i18ngrep "^Interdiff:$" 0000-cover-letter.patch &&
1788        test_i18ngrep ! "^Interdiff:$" 0001-fleep.patch &&
1789        sed "1,/^@@ /d; /^-- $/q" <0000-cover-letter.patch >actual &&
1790        test_cmp expect actual
1791'
1792
1793test_expect_success 'interdiff: reroll-count' '
1794        git format-patch --cover-letter --interdiff=boop~2 -v2 -1 boop &&
1795        test_i18ngrep "^Interdiff ..* v1:$" v2-0000-cover-letter.patch
1796'
1797
1798test_expect_success 'interdiff: solo-patch' '
1799        cat >expect <<-\EOF &&
1800          +fleep
1801
1802        EOF
1803        git format-patch --interdiff=boop~2 -1 boop &&
1804        test_i18ngrep "^Interdiff:$" 0001-fleep.patch &&
1805        sed "1,/^  @@ /d; /^$/q" <0001-fleep.patch >actual &&
1806        test_cmp expect actual
1807'
1808
1809test_done