t / t3701-add-interactive.shon commit Merge branch 'uk/merge-subtree-doc-update' into maint (227124b)
   1#!/bin/sh
   2
   3test_description='add -i basic tests'
   4. ./test-lib.sh
   5. "$TEST_DIRECTORY"/lib-terminal.sh
   6
   7if ! test_have_prereq PERL
   8then
   9        skip_all='skipping add -i tests, perl not available'
  10        test_done
  11fi
  12
  13diff_cmp () {
  14        for x
  15        do
  16                sed  -e '/^index/s/[0-9a-f]*[1-9a-f][0-9a-f]*\.\./1234567../' \
  17                     -e '/^index/s/\.\.[0-9a-f]*[1-9a-f][0-9a-f]*/..9abcdef/' \
  18                     -e '/^index/s/ 00*\.\./ 0000000../' \
  19                     -e '/^index/s/\.\.00*$/..0000000/' \
  20                     -e '/^index/s/\.\.00* /..0000000 /' \
  21                     "$x" >"$x.filtered"
  22        done
  23        test_cmp "$1.filtered" "$2.filtered"
  24}
  25
  26test_expect_success 'setup (initial)' '
  27        echo content >file &&
  28        git add file &&
  29        echo more >>file &&
  30        echo lines >>file
  31'
  32test_expect_success 'status works (initial)' '
  33        git add -i </dev/null >output &&
  34        grep "+1/-0 *+2/-0 file" output
  35'
  36
  37test_expect_success 'setup expected' '
  38        cat >expected <<-\EOF
  39        new file mode 100644
  40        index 0000000..d95f3ad
  41        --- /dev/null
  42        +++ b/file
  43        @@ -0,0 +1 @@
  44        +content
  45        EOF
  46'
  47
  48test_expect_success 'diff works (initial)' '
  49        test_write_lines d 1 | git add -i >output &&
  50        sed -ne "/new file/,/content/p" <output >diff &&
  51        diff_cmp expected diff
  52'
  53test_expect_success 'revert works (initial)' '
  54        git add file &&
  55        test_write_lines r 1 | git add -i &&
  56        git ls-files >output &&
  57        ! grep . output
  58'
  59
  60test_expect_success 'setup (commit)' '
  61        echo baseline >file &&
  62        git add file &&
  63        git commit -m commit &&
  64        echo content >>file &&
  65        git add file &&
  66        echo more >>file &&
  67        echo lines >>file
  68'
  69test_expect_success 'status works (commit)' '
  70        git add -i </dev/null >output &&
  71        grep "+1/-0 *+2/-0 file" output
  72'
  73
  74test_expect_success 'setup expected' '
  75        cat >expected <<-\EOF
  76        index 180b47c..b6f2c08 100644
  77        --- a/file
  78        +++ b/file
  79        @@ -1 +1,2 @@
  80         baseline
  81        +content
  82        EOF
  83'
  84
  85test_expect_success 'diff works (commit)' '
  86        test_write_lines d 1 | git add -i >output &&
  87        sed -ne "/^index/,/content/p" <output >diff &&
  88        diff_cmp expected diff
  89'
  90test_expect_success 'revert works (commit)' '
  91        git add file &&
  92        test_write_lines r 1 | git add -i &&
  93        git add -i </dev/null >output &&
  94        grep "unchanged *+3/-0 file" output
  95'
  96
  97
  98test_expect_success 'setup expected' '
  99        cat >expected <<-\EOF
 100        EOF
 101'
 102
 103test_expect_success 'dummy edit works' '
 104        test_set_editor : &&
 105        test_write_lines e a | git add -p &&
 106        git diff > diff &&
 107        diff_cmp expected diff
 108'
 109
 110test_expect_success 'setup patch' '
 111        cat >patch <<-\EOF
 112        @@ -1,1 +1,4 @@
 113         this
 114        +patch
 115        -does not
 116         apply
 117        EOF
 118'
 119
 120test_expect_success 'setup fake editor' '
 121        write_script "fake_editor.sh" <<-\EOF &&
 122        mv -f "$1" oldpatch &&
 123        mv -f patch "$1"
 124        EOF
 125        test_set_editor "$(pwd)/fake_editor.sh"
 126'
 127
 128test_expect_success 'bad edit rejected' '
 129        git reset &&
 130        test_write_lines e n d | git add -p >output &&
 131        grep "hunk does not apply" output
 132'
 133
 134test_expect_success 'setup patch' '
 135        cat >patch <<-\EOF
 136        this patch
 137        is garbage
 138        EOF
 139'
 140
 141test_expect_success 'garbage edit rejected' '
 142        git reset &&
 143        test_write_lines e n d | git add -p >output &&
 144        grep "hunk does not apply" output
 145'
 146
 147test_expect_success 'setup patch' '
 148        cat >patch <<-\EOF
 149        @@ -1,0 +1,0 @@
 150         baseline
 151        +content
 152        +newcontent
 153        +lines
 154        EOF
 155'
 156
 157test_expect_success 'setup expected' '
 158        cat >expected <<-\EOF
 159        diff --git a/file b/file
 160        index b5dd6c9..f910ae9 100644
 161        --- a/file
 162        +++ b/file
 163        @@ -1,4 +1,4 @@
 164         baseline
 165         content
 166        -newcontent
 167        +more
 168         lines
 169        EOF
 170'
 171
 172test_expect_success 'real edit works' '
 173        test_write_lines e n d | git add -p &&
 174        git diff >output &&
 175        diff_cmp expected output
 176'
 177
 178test_expect_success 'setup file' '
 179        test_write_lines a "" b "" c >file &&
 180        git add file &&
 181        test_write_lines a "" d "" c >file
 182'
 183
 184test_expect_success 'setup patch' '
 185        SP=" " &&
 186        NULL="" &&
 187        cat >patch <<-EOF
 188        @@ -1,4 +1,4 @@
 189         a
 190        $NULL
 191        -b
 192        +f
 193        $SP
 194        c
 195        EOF
 196'
 197
 198test_expect_success 'setup expected' '
 199        cat >expected <<-EOF
 200        diff --git a/file b/file
 201        index b5dd6c9..f910ae9 100644
 202        --- a/file
 203        +++ b/file
 204        @@ -1,5 +1,5 @@
 205         a
 206        $SP
 207        -f
 208        +d
 209        $SP
 210         c
 211        EOF
 212'
 213
 214test_expect_success 'edit can strip spaces from empty context lines' '
 215        test_write_lines e n q | git add -p 2>error &&
 216        test_must_be_empty error &&
 217        git diff >output &&
 218        diff_cmp expected output
 219'
 220
 221test_expect_success 'skip files similarly as commit -a' '
 222        git reset &&
 223        echo file >.gitignore &&
 224        echo changed >file &&
 225        echo y | git add -p file &&
 226        git diff >output &&
 227        git reset &&
 228        git commit -am commit &&
 229        git diff >expected &&
 230        diff_cmp expected output &&
 231        git reset --hard HEAD^
 232'
 233rm -f .gitignore
 234
 235test_expect_success FILEMODE 'patch does not affect mode' '
 236        git reset --hard &&
 237        echo content >>file &&
 238        chmod +x file &&
 239        printf "n\\ny\\n" | git add -p &&
 240        git show :file | grep content &&
 241        git diff file | grep "new mode"
 242'
 243
 244test_expect_success FILEMODE 'stage mode but not hunk' '
 245        git reset --hard &&
 246        echo content >>file &&
 247        chmod +x file &&
 248        printf "y\\nn\\n" | git add -p &&
 249        git diff --cached file | grep "new mode" &&
 250        git diff          file | grep "+content"
 251'
 252
 253
 254test_expect_success FILEMODE 'stage mode and hunk' '
 255        git reset --hard &&
 256        echo content >>file &&
 257        chmod +x file &&
 258        printf "y\\ny\\n" | git add -p &&
 259        git diff --cached file | grep "new mode" &&
 260        git diff --cached file | grep "+content" &&
 261        test -z "$(git diff file)"
 262'
 263
 264# end of tests disabled when filemode is not usable
 265
 266test_expect_success 'setup again' '
 267        git reset --hard &&
 268        test_chmod +x file &&
 269        echo content >>file
 270'
 271
 272# Write the patch file with a new line at the top and bottom
 273test_expect_success 'setup patch' '
 274        cat >patch <<-\EOF
 275        index 180b47c..b6f2c08 100644
 276        --- a/file
 277        +++ b/file
 278        @@ -1,2 +1,4 @@
 279        +firstline
 280         baseline
 281         content
 282        +lastline
 283        \ No newline at end of file
 284        EOF
 285'
 286
 287# Expected output, diff is similar to the patch but w/ diff at the top
 288test_expect_success 'setup expected' '
 289        echo diff --git a/file b/file >expected &&
 290        cat patch |sed "/^index/s/ 100644/ 100755/" >>expected &&
 291        cat >expected-output <<-\EOF
 292        --- a/file
 293        +++ b/file
 294        @@ -1,2 +1,4 @@
 295        +firstline
 296         baseline
 297         content
 298        +lastline
 299        \ No newline at end of file
 300        @@ -1,2 +1,3 @@
 301        +firstline
 302         baseline
 303         content
 304        @@ -1,2 +2,3 @@
 305         baseline
 306         content
 307        +lastline
 308        \ No newline at end of file
 309        EOF
 310'
 311
 312# Test splitting the first patch, then adding both
 313test_expect_success C_LOCALE_OUTPUT 'add first line works' '
 314        git commit -am "clear local changes" &&
 315        git apply patch &&
 316        printf "%s\n" s y y | git add -p file 2>error |
 317                sed -n -e "s/^Stage this hunk[^@]*\(@@ .*\)/\1/" \
 318                       -e "/^[-+@ \\\\]"/p  >output &&
 319        test_must_be_empty error &&
 320        git diff --cached >diff &&
 321        diff_cmp expected diff &&
 322        test_cmp expected-output output
 323'
 324
 325test_expect_success 'setup expected' '
 326        cat >expected <<-\EOF
 327        diff --git a/non-empty b/non-empty
 328        deleted file mode 100644
 329        index d95f3ad..0000000
 330        --- a/non-empty
 331        +++ /dev/null
 332        @@ -1 +0,0 @@
 333        -content
 334        EOF
 335'
 336
 337test_expect_success 'deleting a non-empty file' '
 338        git reset --hard &&
 339        echo content >non-empty &&
 340        git add non-empty &&
 341        git commit -m non-empty &&
 342        rm non-empty &&
 343        echo y | git add -p non-empty &&
 344        git diff --cached >diff &&
 345        diff_cmp expected diff
 346'
 347
 348test_expect_success 'setup expected' '
 349        cat >expected <<-\EOF
 350        diff --git a/empty b/empty
 351        deleted file mode 100644
 352        index e69de29..0000000
 353        EOF
 354'
 355
 356test_expect_success 'deleting an empty file' '
 357        git reset --hard &&
 358        > empty &&
 359        git add empty &&
 360        git commit -m empty &&
 361        rm empty &&
 362        echo y | git add -p empty &&
 363        git diff --cached >diff &&
 364        diff_cmp expected diff
 365'
 366
 367test_expect_success 'split hunk setup' '
 368        git reset --hard &&
 369        test_write_lines 10 20 30 40 50 60 >test &&
 370        git add test &&
 371        test_tick &&
 372        git commit -m test &&
 373
 374        test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
 375'
 376
 377test_expect_success 'split hunk "add -p (edit)"' '
 378        # Split, say Edit and do nothing.  Then:
 379        #
 380        # 1. Broken version results in a patch that does not apply and
 381        # only takes [y/n] (edit again) so the first q is discarded
 382        # and then n attempts to discard the edit. Repeat q enough
 383        # times to get out.
 384        #
 385        # 2. Correct version applies the (not)edited version, and asks
 386        #    about the next hunk, against which we say q and program
 387        #    exits.
 388        printf "%s\n" s e     q n q q |
 389        EDITOR=: git add -p &&
 390        git diff >actual &&
 391        ! grep "^+15" actual
 392'
 393
 394test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
 395        test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
 396        git reset &&
 397        # test sequence is s(plit), n(o), y(es), e(dit)
 398        # q n q q is there to make sure we exit at the end.
 399        printf "%s\n" s n y e   q n q q |
 400        EDITOR=: git add -p 2>error &&
 401        test_must_be_empty error &&
 402        git diff >actual &&
 403        ! grep "^+31" actual
 404'
 405
 406test_expect_success 'patch mode ignores unmerged entries' '
 407        git reset --hard &&
 408        test_commit conflict &&
 409        test_commit non-conflict &&
 410        git checkout -b side &&
 411        test_commit side conflict.t &&
 412        git checkout master &&
 413        test_commit master conflict.t &&
 414        test_must_fail git merge side &&
 415        echo changed >non-conflict.t &&
 416        echo y | git add -p >output &&
 417        ! grep a/conflict.t output &&
 418        cat >expected <<-\EOF &&
 419        * Unmerged path conflict.t
 420        diff --git a/non-conflict.t b/non-conflict.t
 421        index f766221..5ea2ed4 100644
 422        --- a/non-conflict.t
 423        +++ b/non-conflict.t
 424        @@ -1 +1 @@
 425        -non-conflict
 426        +changed
 427        EOF
 428        git diff --cached >diff &&
 429        diff_cmp expected diff
 430'
 431
 432test_expect_success TTY 'diffs can be colorized' '
 433        git reset --hard &&
 434
 435        echo content >test &&
 436        printf y | test_terminal git add -p >output 2>&1 &&
 437
 438        # We do not want to depend on the exact coloring scheme
 439        # git uses for diffs, so just check that we saw some kind of color.
 440        grep "$(printf "\\033")" output
 441'
 442
 443test_expect_success TTY 'diffFilter filters diff' '
 444        git reset --hard &&
 445
 446        echo content >test &&
 447        test_config interactive.diffFilter "sed s/^/foo:/" &&
 448        printf y | test_terminal git add -p >output 2>&1 &&
 449
 450        # avoid depending on the exact coloring or content of the prompts,
 451        # and just make sure we saw our diff prefixed
 452        grep foo:.*content output
 453'
 454
 455test_expect_success TTY 'detect bogus diffFilter output' '
 456        git reset --hard &&
 457
 458        echo content >test &&
 459        test_config interactive.diffFilter "echo too-short" &&
 460        printf y | test_must_fail test_terminal git add -p
 461'
 462
 463test_expect_success 'patch-mode via -i prompts for files' '
 464        git reset --hard &&
 465
 466        echo one >file &&
 467        echo two >test &&
 468        git add -i <<-\EOF &&
 469        patch
 470        test
 471
 472        y
 473        quit
 474        EOF
 475
 476        echo test >expect &&
 477        git diff --cached --name-only >actual &&
 478        diff_cmp expect actual
 479'
 480
 481test_expect_success 'add -p handles globs' '
 482        git reset --hard &&
 483
 484        mkdir -p subdir &&
 485        echo base >one.c &&
 486        echo base >subdir/two.c &&
 487        git add "*.c" &&
 488        git commit -m base &&
 489
 490        echo change >one.c &&
 491        echo change >subdir/two.c &&
 492        git add -p "*.c" <<-\EOF &&
 493        y
 494        y
 495        EOF
 496
 497        cat >expect <<-\EOF &&
 498        one.c
 499        subdir/two.c
 500        EOF
 501        git diff --cached --name-only >actual &&
 502        test_cmp expect actual
 503'
 504
 505test_expect_success 'add -p handles relative paths' '
 506        git reset --hard &&
 507
 508        echo base >relpath.c &&
 509        git add "*.c" &&
 510        git commit -m relpath &&
 511
 512        echo change >relpath.c &&
 513        mkdir -p subdir &&
 514        git -C subdir add -p .. 2>error <<-\EOF &&
 515        y
 516        EOF
 517
 518        test_must_be_empty error &&
 519
 520        cat >expect <<-\EOF &&
 521        relpath.c
 522        EOF
 523        git diff --cached --name-only >actual &&
 524        test_cmp expect actual
 525'
 526
 527test_expect_success 'add -p does not expand argument lists' '
 528        git reset --hard &&
 529
 530        echo content >not-changed &&
 531        git add not-changed &&
 532        git commit -m "add not-changed file" &&
 533
 534        echo change >file &&
 535        GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
 536        y
 537        EOF
 538
 539        # we know that "file" must be mentioned since we actually
 540        # update it, but we want to be sure that our "." pathspec
 541        # was not expanded into the argument list of any command.
 542        # So look only for "not-changed".
 543        ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
 544'
 545
 546test_expect_success 'hunk-editing handles custom comment char' '
 547        git reset --hard &&
 548        echo change >>file &&
 549        test_config core.commentChar "\$" &&
 550        echo e | GIT_EDITOR=true git add -p &&
 551        git diff --exit-code
 552'
 553
 554test_expect_success 'add -p works even with color.ui=always' '
 555        git reset --hard &&
 556        echo change >>file &&
 557        test_config color.ui always &&
 558        echo y | git add -p &&
 559        echo file >expect &&
 560        git diff --cached --name-only >actual &&
 561        test_cmp expect actual
 562'
 563
 564test_expect_success 'setup different kinds of dirty submodules' '
 565        test_create_repo for-submodules &&
 566        (
 567                cd for-submodules &&
 568                test_commit initial &&
 569                test_create_repo dirty-head &&
 570                (
 571                        cd dirty-head &&
 572                        test_commit initial
 573                ) &&
 574                cp -R dirty-head dirty-otherwise &&
 575                cp -R dirty-head dirty-both-ways &&
 576                git add dirty-head &&
 577                git add dirty-otherwise dirty-both-ways &&
 578                git commit -m initial &&
 579
 580                cd dirty-head &&
 581                test_commit updated &&
 582                cd ../dirty-both-ways &&
 583                test_commit updated &&
 584                echo dirty >>initial &&
 585                : >untracked &&
 586                cd ../dirty-otherwise &&
 587                echo dirty >>initial &&
 588                : >untracked
 589        ) &&
 590        git -C for-submodules diff-files --name-only >actual &&
 591        cat >expected <<-\EOF &&
 592        dirty-both-ways
 593        dirty-head
 594        dirty-otherwise
 595        EOF
 596        test_cmp expected actual &&
 597        git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
 598        cat >expected <<-\EOF &&
 599        dirty-both-ways
 600        dirty-head
 601        EOF
 602        test_cmp expected actual
 603'
 604
 605test_expect_success 'status ignores dirty submodules (except HEAD)' '
 606        git -C for-submodules add -i </dev/null >output &&
 607        grep dirty-head output &&
 608        grep dirty-both-ways output &&
 609        ! grep dirty-otherwise output
 610'
 611
 612test_expect_success 'set up pathological context' '
 613        git reset --hard &&
 614        test_write_lines a a a a a a a a a a a >a &&
 615        git add a &&
 616        git commit -m a &&
 617        test_write_lines c b a a a a a a a b a a a a >a &&
 618        test_write_lines     a a a a a a a b a a a a >expected-1 &&
 619        test_write_lines   b a a a a a a a b a a a a >expected-2 &&
 620        # check editing can cope with missing header and deleted context lines
 621        # as well as changes to other lines
 622        test_write_lines +b " a" >patch
 623'
 624
 625test_expect_success 'add -p works with pathological context lines' '
 626        git reset &&
 627        printf "%s\n" n y |
 628        git add -p &&
 629        git cat-file blob :a >actual &&
 630        test_cmp expected-1 actual
 631'
 632
 633test_expect_success 'add -p patch editing works with pathological context lines' '
 634        git reset &&
 635        # n q q below is in case edit fails
 636        printf "%s\n" e y    n q q |
 637        git add -p &&
 638        git cat-file blob :a >actual &&
 639        test_cmp expected-2 actual
 640'
 641
 642test_done