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