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