test-lib: fix non-portable pattern bracket expressions
[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 test_expect_success 'setup (initial)' '
27         echo content >file &&
28         git add file &&
29         echo more >>file &&
30         echo lines >>file
31 '
32 test_expect_success 'status works (initial)' '
33         git add -i </dev/null >output &&
34         grep "+1/-0 *+2/-0 file" output
35 '
36
37 test_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
48 test_expect_success 'diff works (initial)' '
49         test_write_lines d 1 | git add -i >output &&
50         sed -ne "/new file/,/content/p" <output >diff &&
51         diff_cmp expected diff
52 '
53 test_expect_success 'revert works (initial)' '
54         git add file &&
55         test_write_lines r 1 | git add -i &&
56         git ls-files >output &&
57         ! grep . output
58 '
59
60 test_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 '
69 test_expect_success 'status works (commit)' '
70         git add -i </dev/null >output &&
71         grep "+1/-0 *+2/-0 file" output
72 '
73
74 test_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
85 test_expect_success 'diff works (commit)' '
86         test_write_lines d 1 | git add -i >output &&
87         sed -ne "/^index/,/content/p" <output >diff &&
88         diff_cmp expected diff
89 '
90 test_expect_success 'revert works (commit)' '
91         git add file &&
92         test_write_lines r 1 | git add -i &&
93         git add -i </dev/null >output &&
94         grep "unchanged *+3/-0 file" output
95 '
96
97
98 test_expect_success 'setup expected' '
99         cat >expected <<-\EOF
100         EOF
101 '
102
103 test_expect_success 'dummy edit works' '
104         test_set_editor : &&
105         test_write_lines e a | git add -p &&
106         git diff > diff &&
107         diff_cmp expected diff
108 '
109
110 test_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
120 test_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
128 test_expect_success 'bad edit rejected' '
129         git reset &&
130         test_write_lines e n d | git add -p >output &&
131         grep "hunk does not apply" output
132 '
133
134 test_expect_success 'setup patch' '
135         cat >patch <<-\EOF
136         this patch
137         is garbage
138         EOF
139 '
140
141 test_expect_success 'garbage edit rejected' '
142         git reset &&
143         test_write_lines e n d | git add -p >output &&
144         grep "hunk does not apply" output
145 '
146
147 test_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
157 test_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
172 test_expect_success 'real edit works' '
173         test_write_lines e n d | git add -p &&
174         git diff >output &&
175         diff_cmp expected output
176 '
177
178 test_expect_success 'setup file' '
179         test_write_lines a "" b "" c >file &&
180         git add file &&
181         test_write_lines a "" d "" c >file
182 '
183
184 test_expect_success 'setup patch' '
185         SP=" " &&
186         NULL="" &&
187         cat >patch <<-EOF
188         @@ -1,4 +1,4 @@
189          a
190         $NULL
191         -b
192         +f
193         $SP
194         c
195         EOF
196 '
197
198 test_expect_success 'setup expected' '
199         cat >expected <<-EOF
200         diff --git a/file b/file
201         index b5dd6c9..f910ae9 100644
202         --- a/file
203         +++ b/file
204         @@ -1,5 +1,5 @@
205          a
206         $SP
207         -f
208         +d
209         $SP
210          c
211         EOF
212 '
213
214 test_expect_success 'edit can strip spaces from empty context lines' '
215         test_write_lines e n q | git add -p 2>error &&
216         test_must_be_empty error &&
217         git diff >output &&
218         diff_cmp expected output
219 '
220
221 test_expect_success 'skip files similarly as commit -a' '
222         git reset &&
223         echo file >.gitignore &&
224         echo changed >file &&
225         echo y | git add -p file &&
226         git diff >output &&
227         git reset &&
228         git commit -am commit &&
229         git diff >expected &&
230         diff_cmp expected output &&
231         git reset --hard HEAD^
232 '
233 rm -f .gitignore
234
235 test_expect_success FILEMODE 'patch does not affect mode' '
236         git reset --hard &&
237         echo content >>file &&
238         chmod +x file &&
239         printf "n\\ny\\n" | git add -p &&
240         git show :file | grep content &&
241         git diff file | grep "new mode"
242 '
243
244 test_expect_success FILEMODE 'stage mode but not hunk' '
245         git reset --hard &&
246         echo content >>file &&
247         chmod +x file &&
248         printf "y\\nn\\n" | git add -p &&
249         git diff --cached file | grep "new mode" &&
250         git diff          file | grep "+content"
251 '
252
253
254 test_expect_success FILEMODE 'stage mode and hunk' '
255         git reset --hard &&
256         echo content >>file &&
257         chmod +x file &&
258         printf "y\\ny\\n" | git add -p &&
259         git diff --cached file | grep "new mode" &&
260         git diff --cached file | grep "+content" &&
261         test -z "$(git diff file)"
262 '
263
264 # end of tests disabled when filemode is not usable
265
266 test_expect_success 'setup again' '
267         git reset --hard &&
268         test_chmod +x file &&
269         echo content >>file
270 '
271
272 # Write the patch file with a new line at the top and bottom
273 test_expect_success 'setup patch' '
274         cat >patch <<-\EOF
275         index 180b47c..b6f2c08 100644
276         --- a/file
277         +++ b/file
278         @@ -1,2 +1,4 @@
279         +firstline
280          baseline
281          content
282         +lastline
283         \ No newline at end of file
284         EOF
285 '
286
287 # Expected output, diff is similar to the patch but w/ diff at the top
288 test_expect_success 'setup expected' '
289         echo diff --git a/file b/file >expected &&
290         cat patch |sed "/^index/s/ 100644/ 100755/" >>expected &&
291         cat >expected-output <<-\EOF
292         --- a/file
293         +++ b/file
294         @@ -1,2 +1,4 @@
295         +firstline
296          baseline
297          content
298         +lastline
299         \ No newline at end of file
300         @@ -1,2 +1,3 @@
301         +firstline
302          baseline
303          content
304         @@ -1,2 +2,3 @@
305          baseline
306          content
307         +lastline
308         \ No newline at end of file
309         EOF
310 '
311
312 # Test splitting the first patch, then adding both
313 test_expect_success C_LOCALE_OUTPUT 'add first line works' '
314         git commit -am "clear local changes" &&
315         git apply patch &&
316         printf "%s\n" s y y | git add -p file 2>error |
317                 sed -n -e "s/^Stage this hunk[^@]*\(@@ .*\)/\1/" \
318                        -e "/^[-+@ \\\\]"/p  >output &&
319         test_must_be_empty error &&
320         git diff --cached >diff &&
321         diff_cmp expected diff &&
322         test_cmp expected-output output
323 '
324
325 test_expect_success 'setup expected' '
326         cat >expected <<-\EOF
327         diff --git a/non-empty b/non-empty
328         deleted file mode 100644
329         index d95f3ad..0000000
330         --- a/non-empty
331         +++ /dev/null
332         @@ -1 +0,0 @@
333         -content
334         EOF
335 '
336
337 test_expect_success 'deleting a non-empty file' '
338         git reset --hard &&
339         echo content >non-empty &&
340         git add non-empty &&
341         git commit -m non-empty &&
342         rm non-empty &&
343         echo y | git add -p non-empty &&
344         git diff --cached >diff &&
345         diff_cmp expected diff
346 '
347
348 test_expect_success 'setup expected' '
349         cat >expected <<-\EOF
350         diff --git a/empty b/empty
351         deleted file mode 100644
352         index e69de29..0000000
353         EOF
354 '
355
356 test_expect_success 'deleting an empty file' '
357         git reset --hard &&
358         > empty &&
359         git add empty &&
360         git commit -m empty &&
361         rm empty &&
362         echo y | git add -p empty &&
363         git diff --cached >diff &&
364         diff_cmp expected diff
365 '
366
367 test_expect_success 'split hunk setup' '
368         git reset --hard &&
369         test_write_lines 10 20 30 40 50 60 >test &&
370         git add test &&
371         test_tick &&
372         git commit -m test &&
373
374         test_write_lines 10 15 20 21 22 23 24 30 40 50 60 >test
375 '
376
377 test_expect_success 'split hunk "add -p (edit)"' '
378         # Split, say Edit and do nothing.  Then:
379         #
380         # 1. Broken version results in a patch that does not apply and
381         # only takes [y/n] (edit again) so the first q is discarded
382         # and then n attempts to discard the edit. Repeat q enough
383         # times to get out.
384         #
385         # 2. Correct version applies the (not)edited version, and asks
386         #    about the next hunk, against which we say q and program
387         #    exits.
388         printf "%s\n" s e     q n q q |
389         EDITOR=: git add -p &&
390         git diff >actual &&
391         ! grep "^+15" actual
392 '
393
394 test_expect_failure 'split hunk "add -p (no, yes, edit)"' '
395         test_write_lines 5 10 20 21 30 31 40 50 60 >test &&
396         git reset &&
397         # test sequence is s(plit), n(o), y(es), e(dit)
398         # q n q q is there to make sure we exit at the end.
399         printf "%s\n" s n y e   q n q q |
400         EDITOR=: git add -p 2>error &&
401         test_must_be_empty error &&
402         git diff >actual &&
403         ! grep "^+31" actual
404 '
405
406 test_expect_success 'patch mode ignores unmerged entries' '
407         git reset --hard &&
408         test_commit conflict &&
409         test_commit non-conflict &&
410         git checkout -b side &&
411         test_commit side conflict.t &&
412         git checkout master &&
413         test_commit master conflict.t &&
414         test_must_fail git merge side &&
415         echo changed >non-conflict.t &&
416         echo y | git add -p >output &&
417         ! grep a/conflict.t output &&
418         cat >expected <<-\EOF &&
419         * Unmerged path conflict.t
420         diff --git a/non-conflict.t b/non-conflict.t
421         index f766221..5ea2ed4 100644
422         --- a/non-conflict.t
423         +++ b/non-conflict.t
424         @@ -1 +1 @@
425         -non-conflict
426         +changed
427         EOF
428         git diff --cached >diff &&
429         diff_cmp expected diff
430 '
431
432 test_expect_success TTY 'diffs can be colorized' '
433         git reset --hard &&
434
435         echo content >test &&
436         printf y | test_terminal git add -p >output 2>&1 &&
437
438         # We do not want to depend on the exact coloring scheme
439         # git uses for diffs, so just check that we saw some kind of color.
440         grep "$(printf "\\033")" output
441 '
442
443 test_expect_success TTY 'diffFilter filters diff' '
444         git reset --hard &&
445
446         echo content >test &&
447         test_config interactive.diffFilter "sed s/^/foo:/" &&
448         printf y | test_terminal git add -p >output 2>&1 &&
449
450         # avoid depending on the exact coloring or content of the prompts,
451         # and just make sure we saw our diff prefixed
452         grep foo:.*content output
453 '
454
455 test_expect_success TTY 'detect bogus diffFilter output' '
456         git reset --hard &&
457
458         echo content >test &&
459         test_config interactive.diffFilter "echo too-short" &&
460         printf y | test_must_fail test_terminal git add -p
461 '
462
463 test_expect_success 'patch-mode via -i prompts for files' '
464         git reset --hard &&
465
466         echo one >file &&
467         echo two >test &&
468         git add -i <<-\EOF &&
469         patch
470         test
471
472         y
473         quit
474         EOF
475
476         echo test >expect &&
477         git diff --cached --name-only >actual &&
478         diff_cmp expect actual
479 '
480
481 test_expect_success 'add -p handles globs' '
482         git reset --hard &&
483
484         mkdir -p subdir &&
485         echo base >one.c &&
486         echo base >subdir/two.c &&
487         git add "*.c" &&
488         git commit -m base &&
489
490         echo change >one.c &&
491         echo change >subdir/two.c &&
492         git add -p "*.c" <<-\EOF &&
493         y
494         y
495         EOF
496
497         cat >expect <<-\EOF &&
498         one.c
499         subdir/two.c
500         EOF
501         git diff --cached --name-only >actual &&
502         test_cmp expect actual
503 '
504
505 test_expect_success 'add -p handles relative paths' '
506         git reset --hard &&
507
508         echo base >relpath.c &&
509         git add "*.c" &&
510         git commit -m relpath &&
511
512         echo change >relpath.c &&
513         mkdir -p subdir &&
514         git -C subdir add -p .. 2>error <<-\EOF &&
515         y
516         EOF
517
518         test_must_be_empty error &&
519
520         cat >expect <<-\EOF &&
521         relpath.c
522         EOF
523         git diff --cached --name-only >actual &&
524         test_cmp expect actual
525 '
526
527 test_expect_success 'add -p does not expand argument lists' '
528         git reset --hard &&
529
530         echo content >not-changed &&
531         git add not-changed &&
532         git commit -m "add not-changed file" &&
533
534         echo change >file &&
535         GIT_TRACE=$(pwd)/trace.out git add -p . <<-\EOF &&
536         y
537         EOF
538
539         # we know that "file" must be mentioned since we actually
540         # update it, but we want to be sure that our "." pathspec
541         # was not expanded into the argument list of any command.
542         # So look only for "not-changed".
543         ! grep -E "^trace: (built-in|exec|run_command): .*not-changed" trace.out
544 '
545
546 test_expect_success 'hunk-editing handles custom comment char' '
547         git reset --hard &&
548         echo change >>file &&
549         test_config core.commentChar "\$" &&
550         echo e | GIT_EDITOR=true git add -p &&
551         git diff --exit-code
552 '
553
554 test_expect_success 'add -p works even with color.ui=always' '
555         git reset --hard &&
556         echo change >>file &&
557         test_config color.ui always &&
558         echo y | git add -p &&
559         echo file >expect &&
560         git diff --cached --name-only >actual &&
561         test_cmp expect actual
562 '
563
564 test_expect_success 'setup different kinds of dirty submodules' '
565         test_create_repo for-submodules &&
566         (
567                 cd for-submodules &&
568                 test_commit initial &&
569                 test_create_repo dirty-head &&
570                 (
571                         cd dirty-head &&
572                         test_commit initial
573                 ) &&
574                 cp -R dirty-head dirty-otherwise &&
575                 cp -R dirty-head dirty-both-ways &&
576                 git add dirty-head &&
577                 git add dirty-otherwise dirty-both-ways &&
578                 git commit -m initial &&
579
580                 cd dirty-head &&
581                 test_commit updated &&
582                 cd ../dirty-both-ways &&
583                 test_commit updated &&
584                 echo dirty >>initial &&
585                 : >untracked &&
586                 cd ../dirty-otherwise &&
587                 echo dirty >>initial &&
588                 : >untracked
589         ) &&
590         git -C for-submodules diff-files --name-only >actual &&
591         cat >expected <<-\EOF &&
592         dirty-both-ways
593         dirty-head
594         dirty-otherwise
595         EOF
596         test_cmp expected actual &&
597         git -C for-submodules diff-files --name-only --ignore-submodules=dirty >actual &&
598         cat >expected <<-\EOF &&
599         dirty-both-ways
600         dirty-head
601         EOF
602         test_cmp expected actual
603 '
604
605 test_expect_success 'status ignores dirty submodules (except HEAD)' '
606         git -C for-submodules add -i </dev/null >output &&
607         grep dirty-head output &&
608         grep dirty-both-ways output &&
609         ! grep dirty-otherwise output
610 '
611
612 test_expect_success 'set up pathological context' '
613         git reset --hard &&
614         test_write_lines a a a a a a a a a a a >a &&
615         git add a &&
616         git commit -m a &&
617         test_write_lines c b a a a a a a a b a a a a >a &&
618         test_write_lines     a a a a a a a b a a a a >expected-1 &&
619         test_write_lines   b a a a a a a a b a a a a >expected-2 &&
620         # check editing can cope with missing header and deleted context lines
621         # as well as changes to other lines
622         test_write_lines +b " a" >patch
623 '
624
625 test_expect_success 'add -p works with pathological context lines' '
626         git reset &&
627         printf "%s\n" n y |
628         git add -p &&
629         git cat-file blob :a >actual &&
630         test_cmp expected-1 actual
631 '
632
633 test_expect_success 'add -p patch editing works with pathological context lines' '
634         git reset &&
635         # n q q below is in case edit fails
636         printf "%s\n" e y    n q q |
637         git add -p &&
638         git cat-file blob :a >actual &&
639         test_cmp expected-2 actual
640 '
641
642 test_done