t / t3701-add-interactive.shon commit t/helper: merge test-chmtime into test-tool (0e49649)
   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 TTY 'diffFilter filters diff' '
 401        git reset --hard &&
 402
 403        echo content >test &&
 404        test_config interactive.diffFilter "sed s/^/foo:/" &&
 405        printf y | test_terminal git add -p >output 2>&1 &&
 406
 407        # avoid depending on the exact coloring or content of the prompts,
 408        # and just make sure we saw our diff prefixed
 409        grep foo:.*content output
 410'
 411
 412test_expect_success TTY 'detect bogus diffFilter output' '
 413        git reset --hard &&
 414
 415        echo content >test &&
 416        test_config interactive.diffFilter "echo too-short" &&
 417        printf y | test_must_fail test_terminal git add -p
 418'
 419
 420test_expect_success 'patch-mode via -i prompts for files' '
 421        git reset --hard &&
 422
 423        echo one >file &&
 424        echo two >test &&
 425        git add -i <<-\EOF &&
 426        patch
 427        test
 428
 429        y
 430        quit
 431        EOF
 432
 433        echo test >expect &&
 434        git diff --cached --name-only >actual &&
 435        diff_cmp expect actual
 436'
 437
 438test_expect_success 'add -p handles globs' '
 439        git reset --hard &&
 440
 441        mkdir -p subdir &&
 442        echo base >one.c &&
 443        echo base >subdir/two.c &&
 444        git add "*.c" &&
 445        git commit -m base &&
 446
 447        echo change >one.c &&
 448        echo change >subdir/two.c &&
 449        git add -p "*.c" <<-\EOF &&
 450        y
 451        y
 452        EOF
 453
 454        cat >expect <<-\EOF &&
 455        one.c
 456        subdir/two.c
 457        EOF
 458        git diff --cached --name-only >actual &&
 459        test_cmp expect actual
 460'
 461
 462test_expect_success 'add -p handles relative paths' '
 463        git reset --hard &&
 464
 465        echo base >relpath.c &&
 466        git add "*.c" &&
 467        git commit -m relpath &&
 468
 469        echo change >relpath.c &&
 470        mkdir -p subdir &&
 471        git -C subdir add -p .. 2>error <<-\EOF &&
 472        y
 473        EOF
 474
 475        test_must_be_empty error &&
 476
 477        cat >expect <<-\EOF &&
 478        relpath.c
 479        EOF
 480        git diff --cached --name-only >actual &&
 481        test_cmp expect actual
 482'
 483
 484test_expect_success 'add -p does not expand argument lists' '
 485        git reset --hard &&
 486
 487        echo content >not-changed &&
 488        git add not-changed &&
 489        git commit -m "add not-changed file" &&
 490
 491        echo change >file &&
 492        GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
 493        y
 494        EOF
 495
 496        # we know that "file" must be mentioned since we actually
 497        # update it, but we want to be sure that our "." pathspec
 498        # was not expanded into the argument list of any command.
 499        # So look only for "not-changed".
 500        ! grep not-changed trace.out
 501'
 502
 503test_expect_success 'hunk-editing handles custom comment char' '
 504        git reset --hard &&
 505        echo change >>file &&
 506        test_config core.commentChar "\$" &&
 507        echo e | GIT_EDITOR=true git add -p &&
 508        git diff --exit-code
 509'
 510
 511test_expect_success 'add -p works even with color.ui=always' '
 512        git reset --hard &&
 513        echo change >>file &&
 514        test_config color.ui always &&
 515        echo y | git add -p &&
 516        echo file >expect &&
 517        git diff --cached --name-only >actual &&
 518        test_cmp expect actual
 519'
 520
 521test_expect_success 'setup different kinds of dirty submodules' '
 522        test_create_repo for-submodules &&
 523        (
 524                cd for-submodules &&
 525                test_commit initial &&
 526                test_create_repo dirty-head &&
 527                (
 528                        cd dirty-head &&
 529                        test_commit initial
 530                ) &&
 531                cp -R dirty-head dirty-otherwise &&
 532                cp -R dirty-head dirty-both-ways &&
 533                git add dirty-head &&
 534                git add dirty-otherwise dirty-both-ways &&
 535                git commit -m initial &&
 536
 537                cd dirty-head &&
 538                test_commit updated &&
 539                cd ../dirty-both-ways &&
 540                test_commit updated &&
 541                echo dirty >>initial &&
 542                : >untracked &&
 543                cd ../dirty-otherwise &&
 544                echo dirty >>initial &&
 545                : >untracked
 546        ) &&
 547        git -C for-submodules diff-files --name-only >actual &&
 548        cat >expected <<-\EOF &&
 549        dirty-both-ways
 550        dirty-head
 551        dirty-otherwise
 552        EOF
 553        test_cmp expected actual &&
 554        git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
 555        cat >expected <<-\EOF &&
 556        dirty-both-ways
 557        dirty-head
 558        EOF
 559        test_cmp expected actual
 560'
 561
 562test_expect_success 'status ignores dirty submodules (except HEAD)' '
 563        git -C for-submodules add -i </dev/null >output &&
 564        grep dirty-head output &&
 565        grep dirty-both-ways output &&
 566        ! grep dirty-otherwise output
 567'
 568
 569test_expect_success 'set up pathological context' '
 570        git reset --hard &&
 571        test_write_lines a a a a a a a a a a a >a &&
 572        git add a &&
 573        git commit -m a &&
 574        test_write_lines c b a a a a a a a b a a a a >a &&
 575        test_write_lines     a a a a a a a b a a a a >expected-1 &&
 576        test_write_lines   b a a a a a a a b a a a a >expected-2 &&
 577        # check editing can cope with missing header and deleted context lines
 578        # as well as changes to other lines
 579        test_write_lines +b " a" >patch
 580'
 581
 582test_expect_success 'add -p works with pathological context lines' '
 583        git reset &&
 584        printf "%s\n" n y |
 585        git add -p &&
 586        git cat-file blob :a >actual &&
 587        test_cmp expected-1 actual
 588'
 589
 590test_expect_success 'add -p patch editing works with pathological context lines' '
 591        git reset &&
 592        # n q q below is in case edit fails
 593        printf "%s\n" e y    n q q |
 594        git add -p &&
 595        git cat-file blob :a >actual &&
 596        test_cmp expected-2 actual
 597'
 598
 599test_done