Merge branch 'al/ref-filter-merged-and-no-merged'
[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 'colorized diffs respect diff.wsErrorHighlight' '
593         git reset --hard &&
594
595         echo "old " >test &&
596         git add test &&
597         echo "new " >test &&
598
599         printf y >y &&
600         force_color git -c diff.wsErrorHighlight=all add -p >output.raw 2>&1 <y &&
601         test_decode_color <output.raw >output &&
602         grep "old<" output
603 '
604
605 test_expect_success 'diffFilter filters diff' '
606         git reset --hard &&
607
608         echo content >test &&
609         test_config interactive.diffFilter "sed s/^/foo:/" &&
610         printf y >y &&
611         force_color git add -p >output 2>&1 <y &&
612
613         # avoid depending on the exact coloring or content of the prompts,
614         # and just make sure we saw our diff prefixed
615         grep foo:.*content output
616 '
617
618 test_expect_success 'detect bogus diffFilter output' '
619         git reset --hard &&
620
621         echo content >test &&
622         test_config interactive.diffFilter "sed 1d" &&
623         printf y >y &&
624         force_color test_must_fail git add -p <y
625 '
626
627 test_expect_success 'diff.algorithm is passed to `git diff-files`' '
628         git reset --hard &&
629
630         >file &&
631         git add file &&
632         echo changed >file &&
633         test_must_fail git -c diff.algorithm=bogus add -p 2>err &&
634         test_i18ngrep "error: option diff-algorithm accepts " err
635 '
636
637 test_expect_success 'patch-mode via -i prompts for files' '
638         git reset --hard &&
639
640         echo one >file &&
641         echo two >test &&
642         git add -i <<-\EOF &&
643         patch
644         test
645
646         y
647         quit
648         EOF
649
650         echo test >expect &&
651         git diff --cached --name-only >actual &&
652         diff_cmp expect actual
653 '
654
655 test_expect_success 'add -p handles globs' '
656         git reset --hard &&
657
658         mkdir -p subdir &&
659         echo base >one.c &&
660         echo base >subdir/two.c &&
661         git add "*.c" &&
662         git commit -m base &&
663
664         echo change >one.c &&
665         echo change >subdir/two.c &&
666         git add -p "*.c" <<-\EOF &&
667         y
668         y
669         EOF
670
671         cat >expect <<-\EOF &&
672         one.c
673         subdir/two.c
674         EOF
675         git diff --cached --name-only >actual &&
676         test_cmp expect actual
677 '
678
679 test_expect_success 'add -p handles relative paths' '
680         git reset --hard &&
681
682         echo base >relpath.c &&
683         git add "*.c" &&
684         git commit -m relpath &&
685
686         echo change >relpath.c &&
687         mkdir -p subdir &&
688         git -C subdir add -p .. 2>error <<-\EOF &&
689         y
690         EOF
691
692         test_must_be_empty error &&
693
694         cat >expect <<-\EOF &&
695         relpath.c
696         EOF
697         git diff --cached --name-only >actual &&
698         test_cmp expect actual
699 '
700
701 test_expect_success 'add -p does not expand argument lists' '
702         git reset --hard &&
703
704         echo content >not-changed &&
705         git add not-changed &&
706         git commit -m "add not-changed file" &&
707
708         echo change >file &&
709         GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
710         y
711         EOF
712
713         # we know that "file" must be mentioned since we actually
714         # update it, but we want to be sure that our "." pathspec
715         # was not expanded into the argument list of any command.
716         # So look only for "not-changed".
717         ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
718 '
719
720 test_expect_success 'hunk-editing handles custom comment char' '
721         git reset --hard &&
722         echo change >>file &&
723         test_config core.commentChar "\$" &&
724         echo e | GIT_EDITOR=true git add -p &&
725         git diff --exit-code
726 '
727
728 test_expect_success 'add -p works even with color.ui=always' '
729         git reset --hard &&
730         echo change >>file &&
731         test_config color.ui always &&
732         echo y | git add -p &&
733         echo file >expect &&
734         git diff --cached --name-only >actual &&
735         test_cmp expect actual
736 '
737
738 test_expect_success 'setup different kinds of dirty submodules' '
739         test_create_repo for-submodules &&
740         (
741                 cd for-submodules &&
742                 test_commit initial &&
743                 test_create_repo dirty-head &&
744                 (
745                         cd dirty-head &&
746                         test_commit initial
747                 ) &&
748                 cp -R dirty-head dirty-otherwise &&
749                 cp -R dirty-head dirty-both-ways &&
750                 git add dirty-head &&
751                 git add dirty-otherwise dirty-both-ways &&
752                 git commit -m initial &&
753
754                 cd dirty-head &&
755                 test_commit updated &&
756                 cd ../dirty-both-ways &&
757                 test_commit updated &&
758                 echo dirty >>initial &&
759                 : >untracked &&
760                 cd ../dirty-otherwise &&
761                 echo dirty >>initial &&
762                 : >untracked
763         ) &&
764         git -C for-submodules diff-files --name-only >actual &&
765         cat >expected <<-\EOF &&
766         dirty-both-ways
767         dirty-head
768         dirty-otherwise
769         EOF
770         test_cmp expected actual &&
771         git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
772         cat >expected <<-\EOF &&
773         dirty-both-ways
774         dirty-head
775         EOF
776         test_cmp expected actual
777 '
778
779 test_expect_success 'status ignores dirty submodules (except HEAD)' '
780         git -C for-submodules add -i </dev/null >output &&
781         grep dirty-head output &&
782         grep dirty-both-ways output &&
783         ! grep dirty-otherwise output
784 '
785
786 test_expect_success 'set up pathological context' '
787         git reset --hard &&
788         test_write_lines a a a a a a a a a a a >a &&
789         git add a &&
790         git commit -m a &&
791         test_write_lines c b a a a a a a a b a a a a >a &&
792         test_write_lines     a a a a a a a b a a a a >expected-1 &&
793         test_write_lines   b a a a a a a a b a a a a >expected-2 &&
794         # check editing can cope with missing header and deleted context lines
795         # as well as changes to other lines
796         test_write_lines +b " a" >patch
797 '
798
799 test_expect_success 'add -p works with pathological context lines' '
800         git reset &&
801         printf "%s\n" n y |
802         git add -p &&
803         git cat-file blob :a >actual &&
804         test_cmp expected-1 actual
805 '
806
807 test_expect_success 'add -p patch editing works with pathological context lines' '
808         git reset &&
809         # n q q below is in case edit fails
810         printf "%s\n" e y    n q q |
811         git add -p &&
812         git cat-file blob :a >actual &&
813         test_cmp expected-2 actual
814 '
815
816 test_expect_success 'checkout -p works with pathological context lines' '
817         test_write_lines a a a a a a >a &&
818         git add a &&
819         test_write_lines a b a b a b a b a b a >a &&
820         test_write_lines s n n y q | git checkout -p &&
821         test_write_lines a b a b a a b a b a >expect &&
822         test_cmp expect a
823 '
824
825 # This should be called from a subshell as it sets a temporary editor
826 setup_new_file() {
827         write_script new-file-editor.sh <<-\EOF &&
828         sed /^#/d "$1" >patch &&
829         sed /^+c/d patch >"$1"
830         EOF
831         test_set_editor "$(pwd)/new-file-editor.sh" &&
832         test_write_lines a b c d e f >new-file &&
833         test_write_lines a b d e f >new-file-expect &&
834         test_write_lines "@@ -0,0 +1,6 @@" +a +b +c +d +e +f >patch-expect
835 }
836
837 test_expect_success 'add -N followed by add -p patch editing' '
838         git reset --hard &&
839         (
840                 setup_new_file &&
841                 git add -N new-file &&
842                 test_write_lines e n q | git add -p &&
843                 git cat-file blob :new-file >actual &&
844                 test_cmp new-file-expect actual &&
845                 test_cmp patch-expect patch
846         )
847 '
848
849 test_expect_success 'checkout -p patch editing of added file' '
850         git reset --hard &&
851         (
852                 setup_new_file &&
853                 git add new-file &&
854                 git commit -m "add new file" &&
855                 git rm new-file &&
856                 git commit -m "remove new file" &&
857                 test_write_lines e n q | git checkout -p HEAD^ &&
858                 test_cmp new-file-expect new-file &&
859                 test_cmp patch-expect patch
860         )
861 '
862
863 test_expect_success 'show help from add--helper' '
864         git reset --hard &&
865         cat >expect <<-EOF &&
866
867         <BOLD>*** Commands ***<RESET>
868           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
869           5: <BOLD;BLUE>p<RESET>atch      6: <BOLD;BLUE>d<RESET>iff       7: <BOLD;BLUE>q<RESET>uit       8: <BOLD;BLUE>h<RESET>elp
870         <BOLD;BLUE>What now<RESET>> <BOLD;RED>status        - show paths with changes<RESET>
871         <BOLD;RED>update        - add working tree state to the staged set of changes<RESET>
872         <BOLD;RED>revert        - revert staged set of changes back to the HEAD version<RESET>
873         <BOLD;RED>patch         - pick hunks and update selectively<RESET>
874         <BOLD;RED>diff          - view diff between HEAD and index<RESET>
875         <BOLD;RED>add untracked - add contents of untracked files to the staged set of changes<RESET>
876         <BOLD>*** Commands ***<RESET>
877           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
878           5: <BOLD;BLUE>p<RESET>atch      6: <BOLD;BLUE>d<RESET>iff       7: <BOLD;BLUE>q<RESET>uit       8: <BOLD;BLUE>h<RESET>elp
879         <BOLD;BLUE>What now<RESET>>$SP
880         Bye.
881         EOF
882         test_write_lines h | force_color git add -i >actual.colored &&
883         test_decode_color <actual.colored >actual &&
884         test_i18ncmp expect actual
885 '
886
887 test_done