t / t3701-add-interactive.shon commit Merge branch 'nd/parseopt-completion' into next (2461b70)
   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        (echo d; echo 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        (echo r; echo 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        (echo d; echo 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        (echo r; echo 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        (echo e; echo 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        (echo e; echo n; echo 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        (echo e; echo n; echo 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        (echo e; echo n; echo d) | git add -p &&
 174        git diff >output &&
 175        diff_cmp expected output
 176'
 177
 178test_expect_success 'skip files similarly as commit -a' '
 179        git reset &&
 180        echo file >.gitignore &&
 181        echo changed >file &&
 182        echo y | git add -p file &&
 183        git diff >output &&
 184        git reset &&
 185        git commit -am commit &&
 186        git diff >expected &&
 187        diff_cmp expected output &&
 188        git reset --hard HEAD^
 189'
 190rm -f .gitignore
 191
 192test_expect_success FILEMODE 'patch does not affect mode' '
 193        git reset --hard &&
 194        echo content >>file &&
 195        chmod +x file &&
 196        printf "n\\ny\\n" | git add -p &&
 197        git show :file | grep content &&
 198        git diff file | grep "new mode"
 199'
 200
 201test_expect_success FILEMODE 'stage mode but not hunk' '
 202        git reset --hard &&
 203        echo content >>file &&
 204        chmod +x file &&
 205        printf "y\\nn\\n" | git add -p &&
 206        git diff --cached file | grep "new mode" &&
 207        git diff          file | grep "+content"
 208'
 209
 210
 211test_expect_success FILEMODE 'stage mode and hunk' '
 212        git reset --hard &&
 213        echo content >>file &&
 214        chmod +x file &&
 215        printf "y\\ny\\n" | git add -p &&
 216        git diff --cached file | grep "new mode" &&
 217        git diff --cached file | grep "+content" &&
 218        test -z "$(git diff file)"
 219'
 220
 221# end of tests disabled when filemode is not usable
 222
 223test_expect_success 'setup again' '
 224        git reset --hard &&
 225        test_chmod +x file &&
 226        echo content >>file
 227'
 228
 229# Write the patch file with a new line at the top and bottom
 230test_expect_success 'setup patch' '
 231        cat >patch <<-\EOF
 232        index 180b47c..b6f2c08 100644
 233        --- a/file
 234        +++ b/file
 235        @@ -1,2 +1,4 @@
 236        +firstline
 237         baseline
 238         content
 239        +lastline
 240        \ No newline at end of file
 241        EOF
 242'
 243
 244# Expected output, diff is similar to the patch but w/ diff at the top
 245test_expect_success 'setup expected' '
 246        echo diff --git a/file b/file >expected &&
 247        cat patch |sed "/^index/s/ 100644/ 100755/" >>expected &&
 248        cat >expected-output <<-\EOF
 249        --- a/file
 250        +++ b/file
 251        @@ -1,2 +1,4 @@
 252        +firstline
 253         baseline
 254         content
 255        +lastline
 256        \ No newline at end of file
 257        @@ -1,2 +1,3 @@
 258        +firstline
 259         baseline
 260         content
 261        @@ -1,2 +2,3 @@
 262         baseline
 263         content
 264        +lastline
 265        \ No newline at end of file
 266        EOF
 267'
 268
 269# Test splitting the first patch, then adding both
 270test_expect_success C_LOCALE_OUTPUT 'add first line works' '
 271        git commit -am "clear local changes" &&
 272        git apply patch &&
 273        printf "%s\n" s y y | git add -p file 2>error |
 274                sed -n -e "s/^Stage this hunk[^@]*\(@@ .*\)/\1/" \
 275                       -e "/^[-+@ \\\\]"/p  >output &&
 276        test_must_be_empty error &&
 277        git diff --cached >diff &&
 278        diff_cmp expected diff &&
 279        test_cmp expected-output output
 280'
 281
 282test_expect_success 'setup expected' '
 283        cat >expected <<-\EOF
 284        diff --git a/non-empty b/non-empty
 285        deleted file mode 100644
 286        index d95f3ad..0000000
 287        --- a/non-empty
 288        +++ /dev/null
 289        @@ -1 +0,0 @@
 290        -content
 291        EOF
 292'
 293
 294test_expect_success 'deleting a non-empty file' '
 295        git reset --hard &&
 296        echo content >non-empty &&
 297        git add non-empty &&
 298        git commit -m non-empty &&
 299        rm non-empty &&
 300        echo y | git add -p non-empty &&
 301        git diff --cached >diff &&
 302        diff_cmp expected diff
 303'
 304
 305test_expect_success 'setup expected' '
 306        cat >expected <<-\EOF
 307        diff --git a/empty b/empty
 308        deleted file mode 100644
 309        index e69de29..0000000
 310        EOF
 311'
 312
 313test_expect_success 'deleting an empty file' '
 314        git reset --hard &&
 315        > empty &&
 316        git add empty &&
 317        git commit -m empty &&
 318        rm empty &&
 319        echo y | git add -p empty &&
 320        git diff --cached >diff &&
 321        diff_cmp expected diff
 322'
 323
 324test_expect_success 'split hunk setup' '
 325        git reset --hard &&
 326        test_write_lines 10 20 30 40 50 60 >test &&
 327        git add test &&
 328        test_tick &&
 329        git commit -m test &&
 330
 331        test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
 332'
 333
 334test_expect_success 'split hunk "add -p (edit)"' '
 335        # Split, say Edit and do nothing.  Then:
 336        #
 337        # 1. Broken version results in a patch that does not apply and
 338        # only takes [y/n] (edit again) so the first q is discarded
 339        # and then n attempts to discard the edit. Repeat q enough
 340        # times to get out.
 341        #
 342        # 2. Correct version applies the (not)edited version, and asks
 343        #    about the next hunk, against which we say q and program
 344        #    exits.
 345        printf "%s\n" s e     q n q q |
 346        EDITOR=: git add -p &&
 347        git diff >actual &&
 348        ! grep "^+15" actual
 349'
 350
 351test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
 352        test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
 353        git reset &&
 354        # test sequence is s(plit), n(o), y(es), e(dit)
 355        # q n q q is there to make sure we exit at the end.
 356        printf "%s\n" s n y e   q n q q |
 357        EDITOR=: git add -p 2>error &&
 358        test_must_be_empty error &&
 359        git diff >actual &&
 360        ! grep "^+31" actual
 361'
 362
 363test_expect_success 'patch mode ignores unmerged entries' '
 364        git reset --hard &&
 365        test_commit conflict &&
 366        test_commit non-conflict &&
 367        git checkout -b side &&
 368        test_commit side conflict.t &&
 369        git checkout master &&
 370        test_commit master conflict.t &&
 371        test_must_fail git merge side &&
 372        echo changed >non-conflict.t &&
 373        echo y | git add -p >output &&
 374        ! grep a/conflict.t output &&
 375        cat >expected <<-\EOF &&
 376        * Unmerged path conflict.t
 377        diff --git a/non-conflict.t b/non-conflict.t
 378        index f766221..5ea2ed4 100644
 379        --- a/non-conflict.t
 380        +++ b/non-conflict.t
 381        @@ -1 +1 @@
 382        -non-conflict
 383        +changed
 384        EOF
 385        git diff --cached >diff &&
 386        diff_cmp expected diff
 387'
 388
 389test_expect_success TTY 'diffs can be colorized' '
 390        git reset --hard &&
 391
 392        echo content >test &&
 393        printf y | test_terminal git add -p >output 2>&1 &&
 394
 395        # We do not want to depend on the exact coloring scheme
 396        # git uses for diffs, so just check that we saw some kind of color.
 397        grep "$(printf "\\033")" output
 398'
 399
 400test_expect_success 'patch-mode via -i prompts for files' '
 401        git reset --hard &&
 402
 403        echo one >file &&
 404        echo two >test &&
 405        git add -i <<-\EOF &&
 406        patch
 407        test
 408
 409        y
 410        quit
 411        EOF
 412
 413        echo test >expect &&
 414        git diff --cached --name-only >actual &&
 415        diff_cmp expect actual
 416'
 417
 418test_expect_success 'add -p handles globs' '
 419        git reset --hard &&
 420
 421        mkdir -p subdir &&
 422        echo base >one.c &&
 423        echo base >subdir/two.c &&
 424        git add "*.c" &&
 425        git commit -m base &&
 426
 427        echo change >one.c &&
 428        echo change >subdir/two.c &&
 429        git add -p "*.c" <<-\EOF &&
 430        y
 431        y
 432        EOF
 433
 434        cat >expect <<-\EOF &&
 435        one.c
 436        subdir/two.c
 437        EOF
 438        git diff --cached --name-only >actual &&
 439        test_cmp expect actual
 440'
 441
 442test_expect_success 'add -p handles relative paths' '
 443        git reset --hard &&
 444
 445        echo base >relpath.c &&
 446        git add "*.c" &&
 447        git commit -m relpath &&
 448
 449        echo change >relpath.c &&
 450        mkdir -p subdir &&
 451        git -C subdir add -p .. 2>error <<-\EOF &&
 452        y
 453        EOF
 454
 455        test_must_be_empty error &&
 456
 457        cat >expect <<-\EOF &&
 458        relpath.c
 459        EOF
 460        git diff --cached --name-only >actual &&
 461        test_cmp expect actual
 462'
 463
 464test_expect_success 'add -p does not expand argument lists' '
 465        git reset --hard &&
 466
 467        echo content >not-changed &&
 468        git add not-changed &&
 469        git commit -m "add not-changed file" &&
 470
 471        echo change >file &&
 472        GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
 473        y
 474        EOF
 475
 476        # we know that "file" must be mentioned since we actually
 477        # update it, but we want to be sure that our "." pathspec
 478        # was not expanded into the argument list of any command.
 479        # So look only for "not-changed".
 480        ! grep not-changed trace.out
 481'
 482
 483test_expect_success 'hunk-editing handles custom comment char' '
 484        git reset --hard &&
 485        echo change >>file &&
 486        test_config core.commentChar "\$" &&
 487        echo e | GIT_EDITOR=true git add -p &&
 488        git diff --exit-code
 489'
 490
 491test_expect_success 'add -p works even with color.ui=always' '
 492        git reset --hard &&
 493        echo change >>file &&
 494        test_config color.ui always &&
 495        echo y | git add -p &&
 496        echo file >expect &&
 497        git diff --cached --name-only >actual &&
 498        test_cmp expect actual
 499'
 500
 501test_expect_success 'setup different kinds of dirty submodules' '
 502        test_create_repo for-submodules &&
 503        (
 504                cd for-submodules &&
 505                test_commit initial &&
 506                test_create_repo dirty-head &&
 507                (
 508                        cd dirty-head &&
 509                        test_commit initial
 510                ) &&
 511                cp -R dirty-head dirty-otherwise &&
 512                cp -R dirty-head dirty-both-ways &&
 513                git add dirty-head &&
 514                git add dirty-otherwise dirty-both-ways &&
 515                git commit -m initial &&
 516
 517                cd dirty-head &&
 518                test_commit updated &&
 519                cd ../dirty-both-ways &&
 520                test_commit updated &&
 521                echo dirty >>initial &&
 522                : >untracked &&
 523                cd ../dirty-otherwise &&
 524                echo dirty >>initial &&
 525                : >untracked
 526        ) &&
 527        git -C for-submodules diff-files --name-only >actual &&
 528        cat >expected <<-\EOF &&
 529        dirty-both-ways
 530        dirty-head
 531        dirty-otherwise
 532        EOF
 533        test_cmp expected actual &&
 534        git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
 535        cat >expected <<-\EOF &&
 536        dirty-both-ways
 537        dirty-head
 538        EOF
 539        test_cmp expected actual
 540'
 541
 542test_expect_success 'status ignores dirty submodules (except HEAD)' '
 543        git -C for-submodules add -i </dev/null >output &&
 544        grep dirty-head output &&
 545        grep dirty-both-ways output &&
 546        ! grep dirty-otherwise output
 547'
 548
 549test_expect_success 'set up pathological context' '
 550        git reset --hard &&
 551        test_write_lines a a a a a a a a a a a >a &&
 552        git add a &&
 553        git commit -m a &&
 554        test_write_lines c b a a a a a a a b a a a a >a &&
 555        test_write_lines     a a a a a a a b a a a a >expected-1 &&
 556        test_write_lines   b a a a a a a a b a a a a >expected-2 &&
 557        # check editing can cope with missing header and deleted context lines
 558        # as well as changes to other lines
 559        test_write_lines +b " a" >patch
 560'
 561
 562test_expect_success 'add -p works with pathological context lines' '
 563        git reset &&
 564        printf "%s\n" n y |
 565        git add -p &&
 566        git cat-file blob :a >actual &&
 567        test_cmp expected-1 actual
 568'
 569
 570test_expect_success 'add -p patch editing works with pathological context lines' '
 571        git reset &&
 572        # n q q below is in case edit fails
 573        printf "%s\n" e y    n q q |
 574        git add -p &&
 575        git cat-file blob :a >actual &&
 576        test_cmp expected-2 actual
 577'
 578
 579test_done