t4129: don't fail if setgid is set in the test directory
[git] / t / t3701-add-interactive.sh
1 #!/bin/sh
2
3 test_description='add -i basic tests'
4 . ./test-lib.sh
5 . "$TEST_DIRECTORY"/lib-terminal.sh
6
7 if ! test_have_prereq PERL
8 then
9         skip_all='skipping add -i tests, perl not available'
10         test_done
11 fi
12
13 diff_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
26 # This function uses a trick to manipulate the interactive add to use color:
27 # the `want_color()` function special-cases the situation where a pager was
28 # spawned and Git now wants to output colored text: to detect that situation,
29 # the environment variable `GIT_PAGER_IN_USE` is set. However, color is
30 # suppressed despite that environment variable if the `TERM` variable
31 # indicates a dumb terminal, so we set that variable, too.
32
33 force_color () {
34         # The first element of $@ may be a shell function, as a result POSIX
35         # does not guarantee that "one-shot assignment" will not persist after
36         # the function call. Thus, we prevent these variables from escaping
37         # this function's context with this subshell.
38         (
39                 GIT_PAGER_IN_USE=true &&
40                 TERM=vt100 &&
41                 export GIT_PAGER_IN_USE TERM &&
42                 "$@"
43         )
44 }
45
46 test_expect_success 'setup (initial)' '
47         echo content >file &&
48         git add file &&
49         echo more >>file &&
50         echo lines >>file
51 '
52 test_expect_success 'status works (initial)' '
53         git add -i </dev/null >output &&
54         grep "+1/-0 *+2/-0 file" output
55 '
56
57 test_expect_success 'setup expected' '
58         cat >expected <<-\EOF
59         new file mode 100644
60         index 0000000..d95f3ad
61         --- /dev/null
62         +++ b/file
63         @@ -0,0 +1 @@
64         +content
65         EOF
66 '
67
68 test_expect_success 'diff works (initial)' '
69         test_write_lines d 1 | git add -i >output &&
70         sed -ne "/new file/,/content/p" <output >diff &&
71         diff_cmp expected diff
72 '
73 test_expect_success 'revert works (initial)' '
74         git add file &&
75         test_write_lines r 1 | git add -i &&
76         git ls-files >output &&
77         ! grep . output
78 '
79
80 test_expect_success 'add untracked (multiple)' '
81         test_when_finished "git reset && rm [1-9]" &&
82         touch $(test_seq 9) &&
83         test_write_lines a "2-5 8-" | git add -i -- [1-9] &&
84         test_write_lines 2 3 4 5 8 9 >expected &&
85         git ls-files [1-9] >output &&
86         test_cmp expected output
87 '
88
89 test_expect_success 'setup (commit)' '
90         echo baseline >file &&
91         git add file &&
92         git commit -m commit &&
93         echo content >>file &&
94         git add file &&
95         echo more >>file &&
96         echo lines >>file
97 '
98 test_expect_success 'status works (commit)' '
99         git add -i </dev/null >output &&
100         grep "+1/-0 *+2/-0 file" output
101 '
102
103 test_expect_success 'setup expected' '
104         cat >expected <<-\EOF
105         index 180b47c..b6f2c08 100644
106         --- a/file
107         +++ b/file
108         @@ -1 +1,2 @@
109          baseline
110         +content
111         EOF
112 '
113
114 test_expect_success 'diff works (commit)' '
115         test_write_lines d 1 | git add -i >output &&
116         sed -ne "/^index/,/content/p" <output >diff &&
117         diff_cmp expected diff
118 '
119 test_expect_success 'revert works (commit)' '
120         git add file &&
121         test_write_lines r 1 | git add -i &&
122         git add -i </dev/null >output &&
123         grep "unchanged *+3/-0 file" output
124 '
125
126 test_expect_success 'setup expected' '
127         cat >expected <<-\EOF
128         EOF
129 '
130
131 test_expect_success 'dummy edit works' '
132         test_set_editor : &&
133         test_write_lines e a | git add -p &&
134         git diff > diff &&
135         diff_cmp expected diff
136 '
137
138 test_expect_success 'setup patch' '
139         cat >patch <<-\EOF
140         @@ -1,1 +1,4 @@
141          this
142         +patch
143         -does not
144          apply
145         EOF
146 '
147
148 test_expect_success 'setup fake editor' '
149         write_script "fake_editor.sh" <<-\EOF &&
150         mv -f "$1" oldpatch &&
151         mv -f patch "$1"
152         EOF
153         test_set_editor "$(pwd)/fake_editor.sh"
154 '
155
156 test_expect_success 'bad edit rejected' '
157         git reset &&
158         test_write_lines e n d | git add -p >output &&
159         grep "hunk does not apply" output
160 '
161
162 test_expect_success 'setup patch' '
163         cat >patch <<-\EOF
164         this patch
165         is garbage
166         EOF
167 '
168
169 test_expect_success 'garbage edit rejected' '
170         git reset &&
171         test_write_lines e n d | git add -p >output &&
172         grep "hunk does not apply" output
173 '
174
175 test_expect_success 'setup patch' '
176         cat >patch <<-\EOF
177         @@ -1,0 +1,0 @@
178          baseline
179         +content
180         +newcontent
181         +lines
182         EOF
183 '
184
185 test_expect_success 'setup expected' '
186         cat >expected <<-\EOF
187         diff --git a/file b/file
188         index b5dd6c9..f910ae9 100644
189         --- a/file
190         +++ b/file
191         @@ -1,4 +1,4 @@
192          baseline
193          content
194         -newcontent
195         +more
196          lines
197         EOF
198 '
199
200 test_expect_success 'real edit works' '
201         test_write_lines e n d | git add -p &&
202         git diff >output &&
203         diff_cmp expected output
204 '
205
206 test_expect_success 'setup file' '
207         test_write_lines a "" b "" c >file &&
208         git add file &&
209         test_write_lines a "" d "" c >file
210 '
211
212 test_expect_success 'setup patch' '
213         SP=" " &&
214         NULL="" &&
215         cat >patch <<-EOF
216         @@ -1,4 +1,4 @@
217          a
218         $NULL
219         -b
220         +f
221         $SP
222         c
223         EOF
224 '
225
226 test_expect_success 'setup expected' '
227         cat >expected <<-EOF
228         diff --git a/file b/file
229         index b5dd6c9..f910ae9 100644
230         --- a/file
231         +++ b/file
232         @@ -1,5 +1,5 @@
233          a
234         $SP
235         -f
236         +d
237         $SP
238          c
239         EOF
240 '
241
242 test_expect_success 'edit can strip spaces from empty context lines' '
243         test_write_lines e n q | git add -p 2>error &&
244         test_must_be_empty error &&
245         git diff >output &&
246         diff_cmp expected output
247 '
248
249 test_expect_success 'skip files similarly as commit -a' '
250         git reset &&
251         echo file >.gitignore &&
252         echo changed >file &&
253         echo y | git add -p file &&
254         git diff >output &&
255         git reset &&
256         git commit -am commit &&
257         git diff >expected &&
258         diff_cmp expected output &&
259         git reset --hard HEAD^
260 '
261 rm -f .gitignore
262
263 test_expect_success FILEMODE 'patch does not affect mode' '
264         git reset --hard &&
265         echo content >>file &&
266         chmod +x file &&
267         printf "n\\ny\\n" | git add -p &&
268         git show :file | grep content &&
269         git diff file | grep "new mode"
270 '
271
272 test_expect_success FILEMODE 'stage mode but not hunk' '
273         git reset --hard &&
274         echo content >>file &&
275         chmod +x file &&
276         printf "y\\nn\\n" | git add -p &&
277         git diff --cached file | grep "new mode" &&
278         git diff          file | grep "+content"
279 '
280
281
282 test_expect_success FILEMODE 'stage mode and hunk' '
283         git reset --hard &&
284         echo content >>file &&
285         chmod +x file &&
286         printf "y\\ny\\n" | git add -p &&
287         git diff --cached file | grep "new mode" &&
288         git diff --cached file | grep "+content" &&
289         test -z "$(git diff file)"
290 '
291
292 # end of tests disabled when filemode is not usable
293
294 test_expect_success 'different prompts for mode change/deleted' '
295         git reset --hard &&
296         >file &&
297         >deleted &&
298         git add --chmod=+x file deleted &&
299         echo changed >file &&
300         rm deleted &&
301         test_write_lines n n n |
302         git -c core.filemode=true add -p >actual &&
303         sed -n "s/^\(([0-9/]*) Stage .*?\).*/\1/p" actual >actual.filtered &&
304         cat >expect <<-\EOF &&
305         (1/1) Stage deletion [y,n,q,a,d,?]?
306         (1/2) Stage mode change [y,n,q,a,d,j,J,g,/,?]?
307         (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]?
308         EOF
309         test_cmp expect actual.filtered
310 '
311
312 test_expect_success 'correct message when there is nothing to do' '
313         git reset --hard &&
314         git add -p 2>err &&
315         test_i18ngrep "No changes" err &&
316         printf "\\0123" >binary &&
317         git add binary &&
318         printf "\\0abc" >binary &&
319         git add -p 2>err &&
320         test_i18ngrep "Only binary files changed" err
321 '
322
323 test_expect_success 'setup again' '
324         git reset --hard &&
325         test_chmod +x file &&
326         echo content >>file
327 '
328
329 # Write the patch file with a new line at the top and bottom
330 test_expect_success 'setup patch' '
331         cat >patch <<-\EOF
332         index 180b47c..b6f2c08 100644
333         --- a/file
334         +++ b/file
335         @@ -1,2 +1,4 @@
336         +firstline
337          baseline
338          content
339         +lastline
340         \ No newline at end of file
341         EOF
342 '
343
344 # Expected output, diff is similar to the patch but w/ diff at the top
345 test_expect_success 'setup expected' '
346         echo diff --git a/file b/file >expected &&
347         cat patch |sed "/^index/s/ 100644/ 100755/" >>expected &&
348         cat >expected-output <<-\EOF
349         --- a/file
350         +++ b/file
351         @@ -1,2 +1,4 @@
352         +firstline
353          baseline
354          content
355         +lastline
356         \ No newline at end of file
357         @@ -1,2 +1,3 @@
358         +firstline
359          baseline
360          content
361         @@ -1,2 +2,3 @@
362          baseline
363          content
364         +lastline
365         \ No newline at end of file
366         EOF
367 '
368
369 # Test splitting the first patch, then adding both
370 test_expect_success C_LOCALE_OUTPUT 'add first line works' '
371         git commit -am "clear local changes" &&
372         git apply patch &&
373         printf "%s\n" s y y | git add -p file 2>error |
374                 sed -n -e "s/^([1-2]\/[1-2]) Stage this hunk[^@]*\(@@ .*\)/\1/" \
375                        -e "/^[-+@ \\\\]"/p  >output &&
376         test_must_be_empty error &&
377         git diff --cached >diff &&
378         diff_cmp expected diff &&
379         test_cmp expected-output output
380 '
381
382 test_expect_success 'setup expected' '
383         cat >expected <<-\EOF
384         diff --git a/non-empty b/non-empty
385         deleted file mode 100644
386         index d95f3ad..0000000
387         --- a/non-empty
388         +++ /dev/null
389         @@ -1 +0,0 @@
390         -content
391         EOF
392 '
393
394 test_expect_success 'deleting a non-empty file' '
395         git reset --hard &&
396         echo content >non-empty &&
397         git add non-empty &&
398         git commit -m non-empty &&
399         rm non-empty &&
400         echo y | git add -p non-empty &&
401         git diff --cached >diff &&
402         diff_cmp expected diff
403 '
404
405 test_expect_success 'setup expected' '
406         cat >expected <<-\EOF
407         diff --git a/empty b/empty
408         deleted file mode 100644
409         index e69de29..0000000
410         EOF
411 '
412
413 test_expect_success 'deleting an empty file' '
414         git reset --hard &&
415         > empty &&
416         git add empty &&
417         git commit -m empty &&
418         rm empty &&
419         echo y | git add -p empty &&
420         git diff --cached >diff &&
421         diff_cmp expected diff
422 '
423
424 test_expect_success 'adding an empty file' '
425         git init added &&
426         (
427                 cd added &&
428                 test_commit initial &&
429                 >empty &&
430                 git add empty &&
431                 test_tick &&
432                 git commit -m empty &&
433                 git tag added-file &&
434                 git reset --hard HEAD^ &&
435                 test_path_is_missing empty &&
436
437                 echo y | git checkout -p added-file -- >actual &&
438                 test_path_is_file empty &&
439                 test_i18ngrep "Apply addition to index and worktree" actual
440         )
441 '
442
443 test_expect_success 'split hunk setup' '
444         git reset --hard &&
445         test_write_lines 10 20 30 40 50 60 >test &&
446         git add test &&
447         test_tick &&
448         git commit -m test &&
449
450         test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
451 '
452
453 test_expect_success 'goto hunk' '
454         test_when_finished "git reset" &&
455         tr _ " " >expect <<-EOF &&
456         (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? + 1:  -1,2 +1,3          +15
457         _ 2:  -2,4 +3,8          +21
458         go to which hunk? @@ -1,2 +1,3 @@
459         _10
460         +15
461         _20
462         (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
463         EOF
464         test_write_lines s y g 1 | git add -p >actual &&
465         tail -n 7 <actual >actual.trimmed &&
466         test_cmp expect actual.trimmed
467 '
468
469 test_expect_success 'navigate to hunk via regex' '
470         test_when_finished "git reset" &&
471         tr _ " " >expect <<-EOF &&
472         (2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? @@ -1,2 +1,3 @@
473         _10
474         +15
475         _20
476         (1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?_
477         EOF
478         test_write_lines s y /1,2 | git add -p >actual &&
479         tail -n 5 <actual >actual.trimmed &&
480         test_cmp expect actual.trimmed
481 '
482
483 test_expect_success 'split hunk "add -p (edit)"' '
484         # Split, say Edit and do nothing.  Then:
485         #
486         # 1. Broken version results in a patch that does not apply and
487         # only takes [y/n] (edit again) so the first q is discarded
488         # and then n attempts to discard the edit. Repeat q enough
489         # times to get out.
490         #
491         # 2. Correct version applies the (not)edited version, and asks
492         #    about the next hunk, against which we say q and program
493         #    exits.
494         printf "%s\n" s e     q n q q |
495         EDITOR=: git add -p &&
496         git diff >actual &&
497         ! grep "^+15" actual
498 '
499
500 test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
501         test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
502         git reset &&
503         # test sequence is s(plit), n(o), y(es), e(dit)
504         # q n q q is there to make sure we exit at the end.
505         printf "%s\n" s n y e   q n q q |
506         EDITOR=: git add -p 2>error &&
507         test_must_be_empty error &&
508         git diff >actual &&
509         ! grep "^+31" actual
510 '
511
512 test_expect_success 'split hunk with incomplete line at end' '
513         git reset --hard &&
514         printf "missing LF" >>test &&
515         git add test &&
516         test_write_lines before 10 20 30 40 50 60 70 >test &&
517         git grep --cached missing &&
518         test_write_lines s n y q | git add -p &&
519         test_must_fail git grep --cached missing &&
520         git grep before &&
521         test_must_fail git grep --cached before
522 '
523
524 test_expect_failure 'edit, adding lines to the first hunk' '
525         test_write_lines 10 11 20 30 40 50 51 60 >test &&
526         git reset &&
527         tr _ " " >patch <<-EOF &&
528         @@ -1,5 +1,6 @@
529         _10
530         +11
531         +12
532         _20
533         +21
534         +22
535         _30
536         EOF
537         # test sequence is s(plit), e(dit), n(o)
538         # q n q q is there to make sure we exit at the end.
539         printf "%s\n" s e n   q n q q |
540         EDITOR=./fake_editor.sh git add -p 2>error &&
541         test_must_be_empty error &&
542         git diff --cached >actual &&
543         grep "^+22" actual
544 '
545
546 test_expect_success 'patch mode ignores unmerged entries' '
547         git reset --hard &&
548         test_commit conflict &&
549         test_commit non-conflict &&
550         git checkout -b side &&
551         test_commit side conflict.t &&
552         git checkout master &&
553         test_commit master conflict.t &&
554         test_must_fail git merge side &&
555         echo changed >non-conflict.t &&
556         echo y | git add -p >output &&
557         ! grep a/conflict.t output &&
558         cat >expected <<-\EOF &&
559         * Unmerged path conflict.t
560         diff --git a/non-conflict.t b/non-conflict.t
561         index f766221..5ea2ed4 100644
562         --- a/non-conflict.t
563         +++ b/non-conflict.t
564         @@ -1 +1 @@
565         -non-conflict
566         +changed
567         EOF
568         git diff --cached >diff &&
569         diff_cmp expected diff
570 '
571
572 test_expect_success 'index is refreshed after applying patch' '
573         git reset --hard &&
574         echo content >test &&
575         printf y | git add -p &&
576         git diff-files --exit-code
577 '
578
579 test_expect_success 'diffs can be colorized' '
580         git reset --hard &&
581
582         echo content >test &&
583         printf y >y &&
584         force_color git add -p >output 2>&1 <y &&
585         git diff-files --exit-code &&
586
587         # We do not want to depend on the exact coloring scheme
588         # git uses for diffs, so just check that we saw some kind of color.
589         grep "$(printf "\\033")" output
590 '
591
592 test_expect_success 'colors can be overridden' '
593         git reset --hard &&
594         test_when_finished "git rm -f color-test" &&
595         test_write_lines context old more-context >color-test &&
596         git add color-test &&
597         test_write_lines context new more-context another-one >color-test &&
598
599         echo trigger an error message >input &&
600         force_color git \
601                 -c color.interactive.error=blue \
602                 add -i 2>err.raw <input &&
603         test_decode_color <err.raw >err &&
604         grep "<BLUE>Huh (trigger)?<RESET>" err &&
605
606         test_write_lines help quit >input &&
607         force_color git \
608                 -c color.interactive.header=red \
609                 -c color.interactive.help=green \
610                 -c color.interactive.prompt=yellow \
611                 add -i >actual.raw <input &&
612         test_decode_color <actual.raw >actual &&
613         cat >expect <<-\EOF &&
614         <RED>           staged     unstaged path<RESET>
615           1:        +3/-0        +2/-1 color-test
616
617         <RED>*** Commands ***<RESET>
618           1: <YELLOW>s<RESET>tatus        2: <YELLOW>u<RESET>pdate        3: <YELLOW>r<RESET>evert        4: <YELLOW>a<RESET>dd untracked
619           5: <YELLOW>p<RESET>atch         6: <YELLOW>d<RESET>iff          7: <YELLOW>q<RESET>uit          8: <YELLOW>h<RESET>elp
620         <YELLOW>What now<RESET>> <GREEN>status        - show paths with changes<RESET>
621         <GREEN>update        - add working tree state to the staged set of changes<RESET>
622         <GREEN>revert        - revert staged set of changes back to the HEAD version<RESET>
623         <GREEN>patch         - pick hunks and update selectively<RESET>
624         <GREEN>diff          - view diff between HEAD and index<RESET>
625         <GREEN>add untracked - add contents of untracked files to the staged set of changes<RESET>
626         <RED>*** Commands ***<RESET>
627           1: <YELLOW>s<RESET>tatus        2: <YELLOW>u<RESET>pdate        3: <YELLOW>r<RESET>evert        4: <YELLOW>a<RESET>dd untracked
628           5: <YELLOW>p<RESET>atch         6: <YELLOW>d<RESET>iff          7: <YELLOW>q<RESET>uit          8: <YELLOW>h<RESET>elp
629         <YELLOW>What now<RESET>> Bye.
630         EOF
631         test_cmp expect actual &&
632
633         : exercise recolor_hunk by editing and then look at the hunk again &&
634         test_write_lines s e K q >input &&
635         force_color git \
636                 -c color.interactive.prompt=yellow \
637                 -c color.diff.meta=italic \
638                 -c color.diff.frag=magenta \
639                 -c color.diff.context=cyan \
640                 -c color.diff.old=bold \
641                 -c color.diff.new=blue \
642                 -c core.editor=touch \
643                 add -p >actual.raw <input &&
644         test_decode_color <actual.raw >actual.decoded &&
645         sed "s/index [0-9a-f]*\\.\\.[0-9a-f]* 100644/<INDEX-LINE>/" <actual.decoded >actual &&
646         cat >expect <<-\EOF &&
647         <ITALIC>diff --git a/color-test b/color-test<RESET>
648         <ITALIC><INDEX-LINE><RESET>
649         <ITALIC>--- a/color-test<RESET>
650         <ITALIC>+++ b/color-test<RESET>
651         <MAGENTA>@@ -1,3 +1,4 @@<RESET>
652         <CYAN> context<RESET>
653         <BOLD>-old<RESET>
654         <BLUE>+<RESET><BLUE>new<RESET>
655         <CYAN> more-context<RESET>
656         <BLUE>+<RESET><BLUE>another-one<RESET>
657         <YELLOW>(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? <RESET><BOLD>Split into 2 hunks.<RESET>
658         <MAGENTA>@@ -1,3 +1,3 @@<RESET>
659         <CYAN> context<RESET>
660         <BOLD>-old<RESET>
661         <BLUE>+<RESET><BLUE>new<RESET>
662         <CYAN> more-context<RESET>
663         <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET><MAGENTA>@@ -3 +3,2 @@<RESET>
664         <CYAN> more-context<RESET>
665         <BLUE>+<RESET><BLUE>another-one<RESET>
666         <YELLOW>(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,?]? <RESET><MAGENTA>@@ -1,3 +1,3 @@<RESET>
667         <CYAN> context<RESET>
668         <BOLD>-old<RESET>
669         <BLUE>+new<RESET>
670         <CYAN> more-context<RESET>
671         <YELLOW>(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? <RESET>
672         EOF
673         test_cmp expect actual
674 '
675
676 test_expect_success 'colorized diffs respect diff.wsErrorHighlight' '
677         git reset --hard &&
678
679         echo "old " >test &&
680         git add test &&
681         echo "new " >test &&
682
683         printf y >y &&
684         force_color git -c diff.wsErrorHighlight=all add -p >output.raw 2>&1 <y &&
685         test_decode_color <output.raw >output &&
686         grep "old<" output
687 '
688
689 test_expect_success 'diffFilter filters diff' '
690         git reset --hard &&
691
692         echo content >test &&
693         test_config interactive.diffFilter "sed s/^/foo:/" &&
694         printf y >y &&
695         force_color git add -p >output 2>&1 <y &&
696
697         # avoid depending on the exact coloring or content of the prompts,
698         # and just make sure we saw our diff prefixed
699         grep foo:.*content output
700 '
701
702 test_expect_success 'detect bogus diffFilter output' '
703         git reset --hard &&
704
705         echo content >test &&
706         test_config interactive.diffFilter "sed 1d" &&
707         printf y >y &&
708         force_color test_must_fail git add -p <y
709 '
710
711 test_expect_success 'diff.algorithm is passed to `git diff-files`' '
712         git reset --hard &&
713
714         >file &&
715         git add file &&
716         echo changed >file &&
717         test_must_fail git -c diff.algorithm=bogus add -p 2>err &&
718         test_i18ngrep "error: option diff-algorithm accepts " err
719 '
720
721 test_expect_success 'patch-mode via -i prompts for files' '
722         git reset --hard &&
723
724         echo one >file &&
725         echo two >test &&
726         git add -i <<-\EOF &&
727         patch
728         test
729
730         y
731         quit
732         EOF
733
734         echo test >expect &&
735         git diff --cached --name-only >actual &&
736         diff_cmp expect actual
737 '
738
739 test_expect_success 'add -p handles globs' '
740         git reset --hard &&
741
742         mkdir -p subdir &&
743         echo base >one.c &&
744         echo base >subdir/two.c &&
745         git add "*.c" &&
746         git commit -m base &&
747
748         echo change >one.c &&
749         echo change >subdir/two.c &&
750         git add -p "*.c" <<-\EOF &&
751         y
752         y
753         EOF
754
755         cat >expect <<-\EOF &&
756         one.c
757         subdir/two.c
758         EOF
759         git diff --cached --name-only >actual &&
760         test_cmp expect actual
761 '
762
763 test_expect_success 'add -p handles relative paths' '
764         git reset --hard &&
765
766         echo base >relpath.c &&
767         git add "*.c" &&
768         git commit -m relpath &&
769
770         echo change >relpath.c &&
771         mkdir -p subdir &&
772         git -C subdir add -p .. 2>error <<-\EOF &&
773         y
774         EOF
775
776         test_must_be_empty error &&
777
778         cat >expect <<-\EOF &&
779         relpath.c
780         EOF
781         git diff --cached --name-only >actual &&
782         test_cmp expect actual
783 '
784
785 test_expect_success 'add -p does not expand argument lists' '
786         git reset --hard &&
787
788         echo content >not-changed &&
789         git add not-changed &&
790         git commit -m "add not-changed file" &&
791
792         echo change >file &&
793         GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
794         y
795         EOF
796
797         # we know that "file" must be mentioned since we actually
798         # update it, but we want to be sure that our "." pathspec
799         # was not expanded into the argument list of any command.
800         # So look only for "not-changed".
801         ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
802 '
803
804 test_expect_success 'hunk-editing handles custom comment char' '
805         git reset --hard &&
806         echo change >>file &&
807         test_config core.commentChar "\$" &&
808         echo e | GIT_EDITOR=true git add -p &&
809         git diff --exit-code
810 '
811
812 test_expect_success 'add -p works even with color.ui=always' '
813         git reset --hard &&
814         echo change >>file &&
815         test_config color.ui always &&
816         echo y | git add -p &&
817         echo file >expect &&
818         git diff --cached --name-only >actual &&
819         test_cmp expect actual
820 '
821
822 test_expect_success 'setup different kinds of dirty submodules' '
823         test_create_repo for-submodules &&
824         (
825                 cd for-submodules &&
826                 test_commit initial &&
827                 test_create_repo dirty-head &&
828                 (
829                         cd dirty-head &&
830                         test_commit initial
831                 ) &&
832                 cp -R dirty-head dirty-otherwise &&
833                 cp -R dirty-head dirty-both-ways &&
834                 git add dirty-head &&
835                 git add dirty-otherwise dirty-both-ways &&
836                 git commit -m initial &&
837
838                 cd dirty-head &&
839                 test_commit updated &&
840                 cd ../dirty-both-ways &&
841                 test_commit updated &&
842                 echo dirty >>initial &&
843                 : >untracked &&
844                 cd ../dirty-otherwise &&
845                 echo dirty >>initial &&
846                 : >untracked
847         ) &&
848         git -C for-submodules diff-files --name-only >actual &&
849         cat >expected <<-\EOF &&
850         dirty-both-ways
851         dirty-head
852         dirty-otherwise
853         EOF
854         test_cmp expected actual &&
855         git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
856         cat >expected <<-\EOF &&
857         dirty-both-ways
858         dirty-head
859         EOF
860         test_cmp expected actual
861 '
862
863 test_expect_success 'status ignores dirty submodules (except HEAD)' '
864         git -C for-submodules add -i </dev/null >output &&
865         grep dirty-head output &&
866         grep dirty-both-ways output &&
867         ! grep dirty-otherwise output
868 '
869
870 test_expect_success 'set up pathological context' '
871         git reset --hard &&
872         test_write_lines a a a a a a a a a a a >a &&
873         git add a &&
874         git commit -m a &&
875         test_write_lines c b a a a a a a a b a a a a >a &&
876         test_write_lines     a a a a a a a b a a a a >expected-1 &&
877         test_write_lines   b a a a a a a a b a a a a >expected-2 &&
878         # check editing can cope with missing header and deleted context lines
879         # as well as changes to other lines
880         test_write_lines +b " a" >patch
881 '
882
883 test_expect_success 'add -p works with pathological context lines' '
884         git reset &&
885         printf "%s\n" n y |
886         git add -p &&
887         git cat-file blob :a >actual &&
888         test_cmp expected-1 actual
889 '
890
891 test_expect_success 'add -p patch editing works with pathological context lines' '
892         git reset &&
893         # n q q below is in case edit fails
894         printf "%s\n" e y    n q q |
895         git add -p &&
896         git cat-file blob :a >actual &&
897         test_cmp expected-2 actual
898 '
899
900 test_expect_success 'checkout -p works with pathological context lines' '
901         test_write_lines a a a a a a >a &&
902         git add a &&
903         test_write_lines a b a b a b a b a b a >a &&
904         test_write_lines s n n y q | git checkout -p &&
905         test_write_lines a b a b a a b a b a >expect &&
906         test_cmp expect a
907 '
908
909 # This should be called from a subshell as it sets a temporary editor
910 setup_new_file() {
911         write_script new-file-editor.sh <<-\EOF &&
912         sed /^#/d "$1" >patch &&
913         sed /^+c/d patch >"$1"
914         EOF
915         test_set_editor "$(pwd)/new-file-editor.sh" &&
916         test_write_lines a b c d e f >new-file &&
917         test_write_lines a b d e f >new-file-expect &&
918         test_write_lines "@@ -0,0 +1,6 @@" +a +b +c +d +e +f >patch-expect
919 }
920
921 test_expect_success 'add -N followed by add -p patch editing' '
922         git reset --hard &&
923         (
924                 setup_new_file &&
925                 git add -N new-file &&
926                 test_write_lines e n q | git add -p &&
927                 git cat-file blob :new-file >actual &&
928                 test_cmp new-file-expect actual &&
929                 test_cmp patch-expect patch
930         )
931 '
932
933 test_expect_success 'checkout -p patch editing of added file' '
934         git reset --hard &&
935         (
936                 setup_new_file &&
937                 git add new-file &&
938                 git commit -m "add new file" &&
939                 git rm new-file &&
940                 git commit -m "remove new file" &&
941                 test_write_lines e n q | git checkout -p HEAD^ &&
942                 test_cmp new-file-expect new-file &&
943                 test_cmp patch-expect patch
944         )
945 '
946
947 test_expect_success 'show help from add--helper' '
948         git reset --hard &&
949         cat >expect <<-EOF &&
950
951         <BOLD>*** Commands ***<RESET>
952           1: <BOLD;BLUE>s<RESET>tatus     2: <BOLD;BLUE>u<RESET>pdate     3: <BOLD;BLUE>r<RESET>evert     4: <BOLD;BLUE>a<RESET>dd untracked
953           5: <BOLD;BLUE>p<RESET>atch      6: <BOLD;BLUE>d<RESET>iff       7: <BOLD;BLUE>q<RESET>uit       8: <BOLD;BLUE>h<RESET>elp
954         <BOLD;BLUE>What now<RESET>> <BOLD;RED>status        - show paths with changes<RESET>
955         <BOLD;RED>update        - add working tree state to the staged set of changes<RESET>
956         <BOLD;RED>revert        - revert staged set of changes back to the HEAD version<RESET>
957         <BOLD;RED>patch         - pick hunks and update selectively<RESET>
958         <BOLD;RED>diff          - view diff between HEAD and index<RESET>
959         <BOLD;RED>add untracked - add contents of untracked files to the staged set of changes<RESET>
960         <BOLD>*** Commands ***<RESET>
961           1: <BOLD;BLUE>s<RESET>tatus     2: <BOLD;BLUE>u<RESET>pdate     3: <BOLD;BLUE>r<RESET>evert     4: <BOLD;BLUE>a<RESET>dd untracked
962           5: <BOLD;BLUE>p<RESET>atch      6: <BOLD;BLUE>d<RESET>iff       7: <BOLD;BLUE>q<RESET>uit       8: <BOLD;BLUE>h<RESET>elp
963         <BOLD;BLUE>What now<RESET>>$SP
964         Bye.
965         EOF
966         test_write_lines h | force_color git add -i >actual.colored &&
967         test_decode_color <actual.colored >actual &&
968         test_i18ncmp expect actual
969 '
970
971 test_done