24ed3f4a224dc0de73b6e38455c4d902fd97fe0f
   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        EOF
 241'
 242
 243# Expected output, similar to the patch but w/ diff at the top
 244test_expect_success 'setup expected' '
 245        cat >expected <<-\EOF
 246        diff --git a/file b/file
 247        index b6f2c08..61b9053 100755
 248        --- a/file
 249        +++ b/file
 250        @@ -1,2 +1,4 @@
 251        +firstline
 252         baseline
 253         content
 254        +lastline
 255        EOF
 256'
 257
 258# Test splitting the first patch, then adding both
 259test_expect_success 'add first line works' '
 260        git commit -am "clear local changes" &&
 261        git apply patch &&
 262        (echo s; echo y; echo y) | git add -p file &&
 263        git diff --cached > diff &&
 264        diff_cmp expected diff
 265'
 266
 267test_expect_success 'setup expected' '
 268        cat >expected <<-\EOF
 269        diff --git a/non-empty b/non-empty
 270        deleted file mode 100644
 271        index d95f3ad..0000000
 272        --- a/non-empty
 273        +++ /dev/null
 274        @@ -1 +0,0 @@
 275        -content
 276        EOF
 277'
 278
 279test_expect_success 'deleting a non-empty file' '
 280        git reset --hard &&
 281        echo content >non-empty &&
 282        git add non-empty &&
 283        git commit -m non-empty &&
 284        rm non-empty &&
 285        echo y | git add -p non-empty &&
 286        git diff --cached >diff &&
 287        diff_cmp expected diff
 288'
 289
 290test_expect_success 'setup expected' '
 291        cat >expected <<-\EOF
 292        diff --git a/empty b/empty
 293        deleted file mode 100644
 294        index e69de29..0000000
 295        EOF
 296'
 297
 298test_expect_success 'deleting an empty file' '
 299        git reset --hard &&
 300        > empty &&
 301        git add empty &&
 302        git commit -m empty &&
 303        rm empty &&
 304        echo y | git add -p empty &&
 305        git diff --cached >diff &&
 306        diff_cmp expected diff
 307'
 308
 309test_expect_success 'split hunk setup' '
 310        git reset --hard &&
 311        test_write_lines 10 20 30 40 50 60 >test &&
 312        git add test &&
 313        test_tick &&
 314        git commit -m test &&
 315
 316        test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
 317'
 318
 319test_expect_success 'split hunk "add -p (edit)"' '
 320        # Split, say Edit and do nothing.  Then:
 321        #
 322        # 1. Broken version results in a patch that does not apply and
 323        # only takes [y/n] (edit again) so the first q is discarded
 324        # and then n attempts to discard the edit. Repeat q enough
 325        # times to get out.
 326        #
 327        # 2. Correct version applies the (not)edited version, and asks
 328        #    about the next hunk, against which we say q and program
 329        #    exits.
 330        printf "%s\n" s e     q n q q |
 331        EDITOR=: git add -p &&
 332        git diff >actual &&
 333        ! grep "^+15" actual
 334'
 335
 336test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
 337        test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
 338        git reset &&
 339        # test sequence is s(plit), n(o), y(es), e(dit)
 340        # q n q q is there to make sure we exit at the end.
 341        printf "%s\n" s n y e   q n q q |
 342        EDITOR=: git add -p 2>error &&
 343        test_must_be_empty error &&
 344        git diff >actual &&
 345        ! grep "^+31" actual
 346'
 347
 348test_expect_success 'patch mode ignores unmerged entries' '
 349        git reset --hard &&
 350        test_commit conflict &&
 351        test_commit non-conflict &&
 352        git checkout -b side &&
 353        test_commit side conflict.t &&
 354        git checkout master &&
 355        test_commit master conflict.t &&
 356        test_must_fail git merge side &&
 357        echo changed >non-conflict.t &&
 358        echo y | git add -p >output &&
 359        ! grep a/conflict.t output &&
 360        cat >expected <<-\EOF &&
 361        * Unmerged path conflict.t
 362        diff --git a/non-conflict.t b/non-conflict.t
 363        index f766221..5ea2ed4 100644
 364        --- a/non-conflict.t
 365        +++ b/non-conflict.t
 366        @@ -1 +1 @@
 367        -non-conflict
 368        +changed
 369        EOF
 370        git diff --cached >diff &&
 371        diff_cmp expected diff
 372'
 373
 374test_expect_success TTY 'diffs can be colorized' '
 375        git reset --hard &&
 376
 377        echo content >test &&
 378        printf y | test_terminal git add -p >output 2>&1 &&
 379
 380        # We do not want to depend on the exact coloring scheme
 381        # git uses for diffs, so just check that we saw some kind of color.
 382        grep "$(printf "\\033")" output
 383'
 384
 385test_expect_success 'patch-mode via -i prompts for files' '
 386        git reset --hard &&
 387
 388        echo one >file &&
 389        echo two >test &&
 390        git add -i <<-\EOF &&
 391        patch
 392        test
 393
 394        y
 395        quit
 396        EOF
 397
 398        echo test >expect &&
 399        git diff --cached --name-only >actual &&
 400        diff_cmp expect actual
 401'
 402
 403test_expect_success 'add -p handles globs' '
 404        git reset --hard &&
 405
 406        mkdir -p subdir &&
 407        echo base >one.c &&
 408        echo base >subdir/two.c &&
 409        git add "*.c" &&
 410        git commit -m base &&
 411
 412        echo change >one.c &&
 413        echo change >subdir/two.c &&
 414        git add -p "*.c" <<-\EOF &&
 415        y
 416        y
 417        EOF
 418
 419        cat >expect <<-\EOF &&
 420        one.c
 421        subdir/two.c
 422        EOF
 423        git diff --cached --name-only >actual &&
 424        test_cmp expect actual
 425'
 426
 427test_expect_success 'add -p handles relative paths' '
 428        git reset --hard &&
 429
 430        echo base >relpath.c &&
 431        git add "*.c" &&
 432        git commit -m relpath &&
 433
 434        echo change >relpath.c &&
 435        mkdir -p subdir &&
 436        git -C subdir add -p .. 2>error <<-\EOF &&
 437        y
 438        EOF
 439
 440        test_must_be_empty error &&
 441
 442        cat >expect <<-\EOF &&
 443        relpath.c
 444        EOF
 445        git diff --cached --name-only >actual &&
 446        test_cmp expect actual
 447'
 448
 449test_expect_success 'add -p does not expand argument lists' '
 450        git reset --hard &&
 451
 452        echo content >not-changed &&
 453        git add not-changed &&
 454        git commit -m "add not-changed file" &&
 455
 456        echo change >file &&
 457        GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
 458        y
 459        EOF
 460
 461        # we know that "file" must be mentioned since we actually
 462        # update it, but we want to be sure that our "." pathspec
 463        # was not expanded into the argument list of any command.
 464        # So look only for "not-changed".
 465        ! grep not-changed trace.out
 466'
 467
 468test_expect_success 'hunk-editing handles custom comment char' '
 469        git reset --hard &&
 470        echo change >>file &&
 471        test_config core.commentChar "\$" &&
 472        echo e | GIT_EDITOR=true git add -p &&
 473        git diff --exit-code
 474'
 475
 476test_expect_success 'add -p works even with color.ui=always' '
 477        git reset --hard &&
 478        echo change >>file &&
 479        test_config color.ui always &&
 480        echo y | git add -p &&
 481        echo file >expect &&
 482        git diff --cached --name-only >actual &&
 483        test_cmp expect actual
 484'
 485
 486test_expect_success 'set up pathological context' '
 487        git reset --hard &&
 488        test_write_lines a a a a a a a a a a a >a &&
 489        git add a &&
 490        git commit -m a &&
 491        test_write_lines c b a a a a a a a b a a a a >a &&
 492        test_write_lines     a a a a a a a b a a a a >expected-1 &&
 493        test_write_lines   b a a a a a a a b a a a a >expected-2 &&
 494        # check editing can cope with missing header and deleted context lines
 495        # as well as changes to other lines
 496        test_write_lines +b " a" >patch
 497'
 498
 499test_expect_success 'add -p works with pathological context lines' '
 500        git reset &&
 501        printf "%s\n" n y |
 502        git add -p &&
 503        git cat-file blob :a >actual &&
 504        test_cmp expected-1 actual
 505'
 506
 507test_expect_success 'add -p patch editing works with pathological context lines' '
 508        git reset &&
 509        # n q q below is in case edit fails
 510        printf "%s\n" e y    n q q |
 511        git add -p &&
 512        git cat-file blob :a >actual &&
 513        test_cmp expected-2 actual
 514'
 515
 516test_done