difftool: don't overwrite modified files
[git] / t / t7800-difftool.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2009, 2010, 2012, 2013 David Aguilar
4 #
5
6 test_description='git-difftool
7
8 Testing basic diff tool invocation
9 '
10
11 . ./test-lib.sh
12
13 difftool_test_setup ()
14 {
15         test_config diff.tool test-tool &&
16         test_config difftool.test-tool.cmd 'cat "$LOCAL"' &&
17         test_config difftool.bogus-tool.cmd false
18 }
19
20 prompt_given ()
21 {
22         prompt="$1"
23         test "$prompt" = "Launch 'test-tool' [Y/n]: branch"
24 }
25
26 stdin_contains ()
27 {
28         grep >/dev/null "$1"
29 }
30
31 stdin_doesnot_contain ()
32 {
33         ! stdin_contains "$1"
34 }
35
36 # Create a file on master and change it on branch
37 test_expect_success PERL 'setup' '
38         echo master >file &&
39         git add file &&
40         git commit -m "added file" &&
41
42         git checkout -b branch master &&
43         echo branch >file &&
44         git commit -a -m "branch changed file" &&
45         git checkout master
46 '
47
48 # Configure a custom difftool.<tool>.cmd and use it
49 test_expect_success PERL 'custom commands' '
50         difftool_test_setup &&
51         test_config difftool.test-tool.cmd "cat \"\$REMOTE\"" &&
52         echo master >expect &&
53         git difftool --no-prompt branch >actual &&
54         test_cmp expect actual &&
55
56         test_config difftool.test-tool.cmd "cat \"\$LOCAL\"" &&
57         echo branch >expect &&
58         git difftool --no-prompt branch >actual &&
59         test_cmp expect actual
60 '
61
62 test_expect_success PERL 'custom tool commands override built-ins' '
63         test_config difftool.vimdiff.cmd "cat \"\$REMOTE\"" &&
64         echo master >expect &&
65         git difftool --tool vimdiff --no-prompt branch >actual &&
66         test_cmp expect actual
67 '
68
69 test_expect_success PERL 'difftool ignores bad --tool values' '
70         : >expect &&
71         test_expect_code 1 \
72                 git difftool --no-prompt --tool=bad-tool branch >actual &&
73         test_cmp expect actual
74 '
75
76 test_expect_success PERL 'difftool forwards arguments to diff' '
77         difftool_test_setup &&
78         >for-diff &&
79         git add for-diff &&
80         echo changes>for-diff &&
81         git add for-diff &&
82         : >expect &&
83         git difftool --cached --no-prompt -- for-diff >actual &&
84         test_cmp expect actual &&
85         git reset -- for-diff &&
86         rm for-diff
87 '
88
89 test_expect_success PERL 'difftool honors --gui' '
90         difftool_test_setup &&
91         test_config merge.tool bogus-tool &&
92         test_config diff.tool bogus-tool &&
93         test_config diff.guitool test-tool &&
94
95         echo branch >expect &&
96         git difftool --no-prompt --gui branch >actual &&
97         test_cmp expect actual
98 '
99
100 test_expect_success PERL 'difftool --gui last setting wins' '
101         difftool_test_setup &&
102         : >expect &&
103         git difftool --no-prompt --gui --no-gui >actual &&
104         test_cmp expect actual &&
105
106         test_config merge.tool bogus-tool &&
107         test_config diff.tool bogus-tool &&
108         test_config diff.guitool test-tool &&
109         echo branch >expect &&
110         git difftool --no-prompt --no-gui --gui branch >actual &&
111         test_cmp expect actual
112 '
113
114 test_expect_success PERL 'difftool --gui works without configured diff.guitool' '
115         difftool_test_setup &&
116         echo branch >expect &&
117         git difftool --no-prompt --gui branch >actual &&
118         test_cmp expect actual
119 '
120
121 # Specify the diff tool using $GIT_DIFF_TOOL
122 test_expect_success PERL 'GIT_DIFF_TOOL variable' '
123         difftool_test_setup &&
124         git config --unset diff.tool &&
125         echo branch >expect &&
126         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
127         test_cmp expect actual
128 '
129
130 # Test the $GIT_*_TOOL variables and ensure
131 # that $GIT_DIFF_TOOL always wins unless --tool is specified
132 test_expect_success PERL 'GIT_DIFF_TOOL overrides' '
133         difftool_test_setup &&
134         test_config diff.tool bogus-tool &&
135         test_config merge.tool bogus-tool &&
136
137         echo branch >expect &&
138         GIT_DIFF_TOOL=test-tool git difftool --no-prompt branch >actual &&
139         test_cmp expect actual &&
140
141         test_config diff.tool bogus-tool &&
142         test_config merge.tool bogus-tool &&
143         GIT_DIFF_TOOL=bogus-tool \
144                 git difftool --no-prompt --tool=test-tool branch >actual &&
145         test_cmp expect actual
146 '
147
148 # Test that we don't have to pass --no-prompt to difftool
149 # when $GIT_DIFFTOOL_NO_PROMPT is true
150 test_expect_success PERL 'GIT_DIFFTOOL_NO_PROMPT variable' '
151         difftool_test_setup &&
152         echo branch >expect &&
153         GIT_DIFFTOOL_NO_PROMPT=true git difftool branch >actual &&
154         test_cmp expect actual
155 '
156
157 # git-difftool supports the difftool.prompt variable.
158 # Test that GIT_DIFFTOOL_PROMPT can override difftool.prompt = false
159 test_expect_success PERL 'GIT_DIFFTOOL_PROMPT variable' '
160         difftool_test_setup &&
161         test_config difftool.prompt false &&
162         echo >input &&
163         GIT_DIFFTOOL_PROMPT=true git difftool branch <input >output &&
164         prompt=$(tail -1 <output) &&
165         prompt_given "$prompt"
166 '
167
168 # Test that we don't have to pass --no-prompt when difftool.prompt is false
169 test_expect_success PERL 'difftool.prompt config variable is false' '
170         difftool_test_setup &&
171         test_config difftool.prompt false &&
172         echo branch >expect &&
173         git difftool branch >actual &&
174         test_cmp expect actual
175 '
176
177 # Test that we don't have to pass --no-prompt when mergetool.prompt is false
178 test_expect_success PERL 'difftool merge.prompt = false' '
179         difftool_test_setup &&
180         test_might_fail git config --unset difftool.prompt &&
181         test_config mergetool.prompt false &&
182         echo branch >expect &&
183         git difftool branch >actual &&
184         test_cmp expect actual
185 '
186
187 # Test that the -y flag can override difftool.prompt = true
188 test_expect_success PERL 'difftool.prompt can overridden with -y' '
189         difftool_test_setup &&
190         test_config difftool.prompt true &&
191         echo branch >expect &&
192         git difftool -y branch >actual &&
193         test_cmp expect actual
194 '
195
196 # Test that the --prompt flag can override difftool.prompt = false
197 test_expect_success PERL 'difftool.prompt can overridden with --prompt' '
198         difftool_test_setup &&
199         test_config difftool.prompt false &&
200         echo >input &&
201         git difftool --prompt branch <input >output &&
202         prompt=$(tail -1 <output) &&
203         prompt_given "$prompt"
204 '
205
206 # Test that the last flag passed on the command-line wins
207 test_expect_success PERL 'difftool last flag wins' '
208         difftool_test_setup &&
209         echo branch >expect &&
210         git difftool --prompt --no-prompt branch >actual &&
211         test_cmp expect actual &&
212         echo >input &&
213         git difftool --no-prompt --prompt branch <input >output &&
214         prompt=$(tail -1 <output) &&
215         prompt_given "$prompt"
216 '
217
218 # git-difftool falls back to git-mergetool config variables
219 # so test that behavior here
220 test_expect_success PERL 'difftool + mergetool config variables' '
221         test_config merge.tool test-tool &&
222         test_config mergetool.test-tool.cmd "cat \$LOCAL" &&
223         echo branch >expect &&
224         git difftool --no-prompt branch >actual &&
225         test_cmp expect actual &&
226
227         # set merge.tool to something bogus, diff.tool to test-tool
228         test_config merge.tool bogus-tool &&
229         test_config diff.tool test-tool &&
230         git difftool --no-prompt branch >actual &&
231         test_cmp expect actual
232 '
233
234 test_expect_success PERL 'difftool.<tool>.path' '
235         test_config difftool.tkdiff.path echo &&
236         git difftool --tool=tkdiff --no-prompt branch >output &&
237         lines=$(grep file output | wc -l) &&
238         test "$lines" -eq 1
239 '
240
241 test_expect_success PERL 'difftool --extcmd=cat' '
242         echo branch >expect &&
243         echo master >>expect &&
244         git difftool --no-prompt --extcmd=cat branch >actual &&
245         test_cmp expect actual
246 '
247
248 test_expect_success PERL 'difftool --extcmd cat' '
249         echo branch >expect &&
250         echo master >>expect &&
251         git difftool --no-prompt --extcmd=cat branch >actual &&
252         test_cmp expect actual
253 '
254
255 test_expect_success PERL 'difftool -x cat' '
256         echo branch >expect &&
257         echo master >>expect &&
258         git difftool --no-prompt -x cat branch >actual &&
259         test_cmp expect actual
260 '
261
262 test_expect_success PERL 'difftool --extcmd echo arg1' '
263         echo file >expect &&
264         git difftool --no-prompt \
265                 --extcmd sh\ -c\ \"echo\ \$1\" branch >actual &&
266         test_cmp expect actual
267 '
268
269 test_expect_success PERL 'difftool --extcmd cat arg1' '
270         echo master >expect &&
271         git difftool --no-prompt \
272                 --extcmd sh\ -c\ \"cat\ \$1\" branch >actual &&
273         test_cmp expect actual
274 '
275
276 test_expect_success PERL 'difftool --extcmd cat arg2' '
277         echo branch >expect &&
278         git difftool --no-prompt \
279                 --extcmd sh\ -c\ \"cat\ \$2\" branch >actual &&
280         test_cmp expect actual
281 '
282
283 # Create a second file on master and a different version on branch
284 test_expect_success PERL 'setup with 2 files different' '
285         echo m2 >file2 &&
286         git add file2 &&
287         git commit -m "added file2" &&
288
289         git checkout branch &&
290         echo br2 >file2 &&
291         git add file2 &&
292         git commit -a -m "branch changed file2" &&
293         git checkout master
294 '
295
296 test_expect_success PERL 'say no to the first file' '
297         (echo n && echo) >input &&
298         git difftool -x cat branch <input >output &&
299         stdin_contains m2 <output &&
300         stdin_contains br2 <output &&
301         stdin_doesnot_contain master <output &&
302         stdin_doesnot_contain branch <output
303 '
304
305 test_expect_success PERL 'say no to the second file' '
306         (echo && echo n) >input &&
307         git difftool -x cat branch <input >output &&
308         stdin_contains master <output &&
309         stdin_contains branch  <output &&
310         stdin_doesnot_contain m2 <output &&
311         stdin_doesnot_contain br2 <output
312 '
313
314 test_expect_success PERL 'difftool --tool-help' '
315         git difftool --tool-help >output &&
316         stdin_contains tool <output
317 '
318
319 test_expect_success PERL 'setup change in subdirectory' '
320         git checkout master &&
321         mkdir sub &&
322         echo master >sub/sub &&
323         git add sub/sub &&
324         git commit -m "added sub/sub" &&
325         echo test >>file &&
326         echo test >>sub/sub &&
327         git add . &&
328         git commit -m "modified both"
329 '
330
331 test_expect_success PERL 'difftool -d' '
332         git difftool -d --extcmd ls branch >output &&
333         stdin_contains sub <output &&
334         stdin_contains file <output
335 '
336
337 test_expect_success PERL 'difftool --dir-diff' '
338         git difftool --dir-diff --extcmd ls branch >output &&
339         stdin_contains sub <output &&
340         stdin_contains file <output
341 '
342
343 test_expect_success PERL 'difftool --dir-diff ignores --prompt' '
344         git difftool --dir-diff --prompt --extcmd ls branch >output &&
345         stdin_contains sub <output &&
346         stdin_contains file <output
347 '
348
349 test_expect_success PERL 'difftool --dir-diff from subdirectory' '
350         (
351                 cd sub &&
352                 git difftool --dir-diff --extcmd ls branch >output &&
353                 stdin_contains sub <output &&
354                 stdin_contains file <output
355         )
356 '
357
358 write_script .git/CHECK_SYMLINKS <<\EOF
359 for f in file file2 sub/sub
360 do
361         echo "$f"
362         readlink "$2/$f"
363 done >actual
364 EOF
365
366 test_expect_success PERL,SYMLINKS 'difftool --dir-diff --symlink without unstaged changes' '
367         cat >expect <<-EOF &&
368         file
369         $(pwd)/file
370         file2
371         $(pwd)/file2
372         sub/sub
373         $(pwd)/sub/sub
374         EOF
375         git difftool --dir-diff --symlink \
376                 --extcmd "./.git/CHECK_SYMLINKS" branch HEAD &&
377         test_cmp actual expect
378 '
379
380 write_script modify-file <<\EOF
381 echo "new content" >file
382 EOF
383
384 test_expect_success PERL 'difftool --no-symlinks does not overwrite working tree file ' '
385         echo "orig content" >file &&
386         git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-file" branch &&
387         echo "new content" >expect &&
388         test_cmp expect file
389 '
390
391 write_script modify-both-files <<\EOF
392 echo "wt content" >file &&
393 echo "tmp content" >"$2/file" &&
394 echo "$2" >tmpdir
395 EOF
396
397 test_expect_success PERL 'difftool --no-symlinks detects conflict ' '
398         (
399                 TMPDIR=$TRASH_DIRECTORY &&
400                 export TMPDIR &&
401                 echo "orig content" >file &&
402                 test_must_fail git difftool --dir-diff --no-symlinks --extcmd "$(pwd)/modify-both-files" branch &&
403                 echo "wt content" >expect &&
404                 test_cmp expect file &&
405                 echo "tmp content" >expect &&
406                 test_cmp expect "$(cat tmpdir)/file"
407         )
408 '
409
410 test_done