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