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