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