mergetool: Use args as pathspec to unmerged files

Mergetool now treats its path arguments as a pathspec (like other git subcommands), restricting action to the given files and directories. Files matching the pathspec are filtered so mergetool only acts on unmerged paths; previously it would assume each path argument was in an unresolved state, and get confused when it couldn't check out their other stages. Running "git mergetool subdir" will prompt to resolve all conflicted blobs under subdir. Signed-off-by: Jonathon Mah <me@JonathonMah.com> Acked-by: David Aguilar <davvid@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathon Mah committed Sep 15, 2011 at 19:12 UTC 3e8e691abe4e1cce73a8a2ef413dada0278e7b3b
3 files changed +72 -69
Documentation/git-mergetool.txt
+4 -3
@@ -16,9 +16,10 @@ Use `git mergetool` to run one of several merge utilities to resolve
16 merge conflicts. It is typically run after 'git merge'.
17
18 If one or more <file> parameters are given, the merge tool program will
19 -be run to resolve differences on each file. If no <file> names are
20 -specified, 'git mergetool' will run the merge tool program on every file
21 -with merge conflicts.
19 +be run to resolve differences on each file (skipping those without
20 +conflicts). Specifying a directory will include all unresolved files in
21 +that path. If no <file> names are specified, 'git mergetool' will run
22 +the merge tool program on every file with merge conflicts.
23
24 OPTIONS
25 -------
git-mergetool.sh
+28 -48
@@ -342,64 +342,44 @@ merge_keep_temporaries="$(git config --bool mergetool.keepTemporaries || echo fa
342
343 last_status=0
344 rollup_status=0
345 -rerere=false
346 -
347 -files_to_merge() {
348 - if test "$rerere" = true
349 - then
350 - git rerere remaining
351 - else
352 - git ls-files -u | sed -e 's/^[^ ]* //' | sort -u
353 - fi
354 -}
355 -
345 +files=
346
347 if test $# -eq 0 ; then
348 cd_to_toplevel
349
350 if test -e "$GIT_DIR/MERGE_RR"
351 then
362 - rerere=true
352 + files=$(git rerere remaining)
353 + else
354 + files=$(git ls-files -u | sed -e 's/^[^ ]* //' | sort -u)
355 fi
356 +else
357 + files=$(git ls-files -u -- "$@" | sed -e 's/^[^ ]* //' | sort -u)
358 +fi
359
365 - files=$(files_to_merge)
366 - if test -z "$files" ; then
367 - echo "No files need merging"
368 - exit 0
369 - fi
360 +if test -z "$files" ; then
361 + echo "No files need merging"
362 + exit 0
363 +fi
364
371 - # Save original stdin
372 - exec 3<&0
365 +# Save original stdin
366 +exec 3<&0
367
374 - printf "Merging:\n"
375 - printf "$files\n"
368 +printf "Merging:\n"
369 +printf "$files\n"
370
377 - files_to_merge |
378 - while IFS= read i
379 - do
380 - if test $last_status -ne 0; then
381 - prompt_after_failed_merge <&3 || exit 1
382 - fi
383 - printf "\n"
384 - merge_file "$i" <&3
385 - last_status=$?
386 - if test $last_status -ne 0; then
387 - rollup_status=1
388 - fi
389 - done
390 -else
391 - while test $# -gt 0; do
392 - if test $last_status -ne 0; then
393 - prompt_after_failed_merge || exit 1
394 - fi
395 - printf "\n"
396 - merge_file "$1"
397 - last_status=$?
398 - if test $last_status -ne 0; then
399 - rollup_status=1
400 - fi
401 - shift
402 - done
403 -fi
371 +IFS='
372 +'; for i in $files
373 +do
374 + if test $last_status -ne 0; then
375 + prompt_after_failed_merge <&3 || exit 1
376 + fi
377 + printf "\n"
378 + merge_file "$i" <&3
379 + last_status=$?
380 + if test $last_status -ne 0; then
381 + rollup_status=1
382 + fi
383 +done
384
385 exit $rollup_status
t/t7610-mergetool.sh
+40 -18
@@ -16,6 +16,7 @@ Testing basic merge tool invocation'
16 test_expect_success 'setup' '
17 git config rerere.enabled true &&
18 echo master >file1 &&
19 + echo master spaced >"spaced name" &&
20 echo master file11 >file11 &&
21 echo master file12 >file12 &&
22 echo master file13 >file13 &&
@@ -30,13 +31,14 @@ test_expect_success 'setup' '
31 git commit -m "Add foo"
32 ) &&
33 git submodule add git://example.com/submod submod &&
33 - git add file1 file1[1-4] subdir/file3 .gitmodules submod &&
34 + git add file1 "spaced name" file1[1-4] subdir/file3 .gitmodules submod &&
35 git commit -m "add initial versions" &&
36
37 git checkout -b branch1 master &&
38 git submodule update -N &&
39 echo branch1 change >file1 &&
40 echo branch1 newfile >file2 &&
41 + echo branch1 spaced >"spaced name" &&
42 echo branch1 change file11 >file11 &&
43 echo branch1 change file13 >file13 &&
44 echo branch1 sub >subdir/file3 &&
@@ -47,7 +49,7 @@ test_expect_success 'setup' '
49 git commit -m "Add bar on branch1" &&
50 git checkout -b submod-branch1
51 ) &&
50 - git add file1 file11 file13 file2 subdir/file3 submod &&
52 + git add file1 "spaced name" file11 file13 file2 subdir/file3 submod &&
53 git rm file12 &&
54 git commit -m "branch1 changes" &&
55
@@ -55,6 +57,7 @@ test_expect_success 'setup' '
57 git submodule update -N &&
58 echo master updated >file1 &&
59 echo master new >file2 &&
60 + echo master updated spaced >"spaced name" &&
61 echo master updated file12 >file12 &&
62 echo master updated file14 >file14 &&
63 echo master new sub >subdir/file3 &&
@@ -65,7 +68,7 @@ test_expect_success 'setup' '
68 git commit -m "Add bar on master" &&
69 git checkout -b submod-master
70 ) &&
68 - git add file1 file12 file14 file2 subdir/file3 submod &&
71 + git add file1 "spaced name" file12 file14 file2 subdir/file3 submod &&
72 git rm file11 &&
73 git commit -m "master updates" &&
74
@@ -78,8 +81,8 @@ test_expect_success 'custom mergetool' '
81 git checkout -b test1 branch1 &&
82 git submodule update -N &&
83 test_must_fail git merge master >/dev/null 2>&1 &&
81 - ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
82 - ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
84 + ( yes "" | git mergetool file1 file1 ) &&
85 + ( yes "" | git mergetool file2 "spaced name" >/dev/null 2>&1 ) &&
86 ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
87 ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
88 ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
@@ -97,6 +100,7 @@ test_expect_success 'mergetool crlf' '
100 test_must_fail git merge master >/dev/null 2>&1 &&
101 ( yes "" | git mergetool file1 >/dev/null 2>&1 ) &&
102 ( yes "" | git mergetool file2 >/dev/null 2>&1 ) &&
103 + ( yes "" | git mergetool "spaced name" >/dev/null 2>&1 ) &&
104 ( yes "" | git mergetool subdir/file3 >/dev/null 2>&1 ) &&
105 ( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
106 ( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
@@ -126,7 +130,7 @@ test_expect_success 'mergetool on file in parent dir' '
130 (
131 cd subdir &&
132 ( yes "" | git mergetool ../file1 >/dev/null 2>&1 ) &&
129 - ( yes "" | git mergetool ../file2 >/dev/null 2>&1 ) &&
133 + ( yes "" | git mergetool ../file2 ../spaced\ name >/dev/null 2>&1 ) &&
134 ( yes "d" | git mergetool ../file11 >/dev/null 2>&1 ) &&
135 ( yes "d" | git mergetool ../file12 >/dev/null 2>&1 ) &&
136 ( yes "l" | git mergetool ../submod >/dev/null 2>&1 ) &&
@@ -180,6 +184,24 @@ test_expect_success 'mergetool skips resolved paths when rerere is active' '
184 git reset --hard
185 '
186
187 +test_expect_success 'mergetool takes partial path' '
188 + git config rerere.enabled false &&
189 + git checkout -b test12 branch1 &&
190 + git submodule update -N &&
191 + test_must_fail git merge master &&
192 +
193 + #shouldnt need these lines
194 + #( yes "d" | git mergetool file11 >/dev/null 2>&1 ) &&
195 + #( yes "d" | git mergetool file12 >/dev/null 2>&1 ) &&
196 + #( yes "l" | git mergetool submod >/dev/null 2>&1 ) &&
197 + #( yes "" | git mergetool file1 file2 >/dev/null 2>&1 ) &&
198 +
199 + ( yes "" | git mergetool subdir ) &&
200 +
201 + test "$(cat subdir/file3)" = "master new sub" &&
202 + git reset --hard
203 +'
204 +
205 test_expect_success 'deleted vs modified submodule' '
206 git checkout -b test6 branch1 &&
207 git submodule update -N &&
@@ -189,7 +211,7 @@ test_expect_success 'deleted vs modified submodule' '
211 git checkout -b test6.a test6 &&
212 test_must_fail git merge master &&
213 test -n "$(git ls-files -u)" &&
192 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
214 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
215 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
216 ( yes "r" | git mergetool submod ) &&
217 rmdir submod && mv submod-movedaside submod &&
@@ -205,7 +227,7 @@ test_expect_success 'deleted vs modified submodule' '
227 git submodule update -N &&
228 test_must_fail git merge master &&
229 test -n "$(git ls-files -u)" &&
208 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
230 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
231 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
232 ( yes "l" | git mergetool submod ) &&
233 test ! -e submod &&
@@ -218,7 +240,7 @@ test_expect_success 'deleted vs modified submodule' '
240 git submodule update -N &&
241 test_must_fail git merge test6 &&
242 test -n "$(git ls-files -u)" &&
221 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
243 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
244 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
245 ( yes "r" | git mergetool submod ) &&
246 test ! -e submod &&
@@ -233,7 +255,7 @@ test_expect_success 'deleted vs modified submodule' '
255 git submodule update -N &&
256 test_must_fail git merge test6 &&
257 test -n "$(git ls-files -u)" &&
236 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
258 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
259 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
260 ( yes "l" | git mergetool submod ) &&
261 test "$(cat submod/bar)" = "master submodule" &&
@@ -256,7 +278,7 @@ test_expect_success 'file vs modified submodule' '
278 git checkout -b test7.a branch1 &&
279 test_must_fail git merge master &&
280 test -n "$(git ls-files -u)" &&
259 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
281 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
282 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
283 ( yes "r" | git mergetool submod ) &&
284 rmdir submod && mv submod-movedaside submod &&
@@ -271,7 +293,7 @@ test_expect_success 'file vs modified submodule' '
293 git checkout -b test7.b test7 &&
294 test_must_fail git merge master &&
295 test -n "$(git ls-files -u)" &&
274 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
296 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
297 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
298 ( yes "l" | git mergetool submod ) &&
299 git submodule update -N &&
@@ -286,7 +308,7 @@ test_expect_success 'file vs modified submodule' '
308 git submodule update -N &&
309 test_must_fail git merge test7 &&
310 test -n "$(git ls-files -u)" &&
289 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
311 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
312 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
313 ( yes "r" | git mergetool submod ) &&
314 test -d submod.orig &&
@@ -301,7 +323,7 @@ test_expect_success 'file vs modified submodule' '
323 git submodule update -N &&
324 test_must_fail git merge test7 &&
325 test -n "$(git ls-files -u)" &&
304 - ( yes "" | git mergetool file1 file2 subdir/file3 >/dev/null 2>&1 ) &&
326 + ( yes "" | git mergetool file1 file2 spaced\ name subdir/file3 >/dev/null 2>&1 ) &&
327 ( yes "d" | git mergetool file11 file12 >/dev/null 2>&1 ) &&
328 ( yes "l" | git mergetool submod ) &&
329 test "$(cat submod/bar)" = "master submodule" &&
@@ -388,7 +410,7 @@ test_expect_success 'directory vs modified submodule' '
410 test "$(cat submod/file16)" = "not a submodule" &&
411 rm -rf submod.orig &&
412
391 - git reset --hard &&
413 + git reset --hard >/dev/null 2>&1 &&
414 test_must_fail git merge master &&
415 test -n "$(git ls-files -u)" &&
416 test ! -e submod.orig &&
@@ -400,7 +422,7 @@ test_expect_success 'directory vs modified submodule' '
422 ( cd submod && git clean -f && git reset --hard ) &&
423 git submodule update -N &&
424 test "$(cat submod/bar)" = "master submodule" &&
403 - git reset --hard && rm -rf submod-movedaside &&
425 + git reset --hard >/dev/null 2>&1 && rm -rf submod-movedaside &&
426
427 git checkout -b test11.c master &&
428 git submodule update -N &&
@@ -410,7 +432,7 @@ test_expect_success 'directory vs modified submodule' '
432 git submodule update -N &&
433 test "$(cat submod/bar)" = "master submodule" &&
434
413 - git reset --hard &&
435 + git reset --hard >/dev/null 2>&1 &&
436 git submodule update -N &&
437 test_must_fail git merge test11 &&
438 test -n "$(git ls-files -u)" &&
@@ -418,7 +440,7 @@ test_expect_success 'directory vs modified submodule' '
440 ( yes "r" | git mergetool submod ) &&
441 test "$(cat submod/file16)" = "not a submodule" &&
442
421 - git reset --hard master &&
443 + git reset --hard master >/dev/null 2>&1 &&
444 ( cd submod && git clean -f && git reset --hard ) &&
445 git submodule update -N
446 '