Skip to content

Commit 78a26cb

Browse files
committed
Merge branch 'sh/mergetool-hideresolved'
"git mergetool" feeds three versions (base, local and remote) of a conflicted path unmodified. The command learned to optionally prepare these files with unconflicted parts already resolved. * sh/mergetool-hideresolved: mergetool: add per-tool support and overrides for the hideResolved flag mergetool: break setup_tool out into separate initialization function mergetool: add hideResolved configuration
2 parents aa2d3db + 9d9cf23 commit 78a26cb

File tree

6 files changed

+101
-3
lines changed

6 files changed

+101
-3
lines changed

Documentation/config/mergetool.txt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ mergetool.<tool>.cmd::
1313
merged; 'MERGED' contains the name of the file to which the merge
1414
tool should write the results of a successful merge.
1515

16+
mergetool.<tool>.hideResolved::
17+
Allows the user to override the global `mergetool.hideResolved` value
18+
for a specific tool. See `mergetool.hideResolved` for the full
19+
description.
20+
1621
mergetool.<tool>.trustExitCode::
1722
For a custom merge command, specify whether the exit code of
1823
the merge command can be used to determine whether the merge was
@@ -40,6 +45,16 @@ mergetool.meld.useAutoMerge::
4045
value of `false` avoids using `--auto-merge` altogether, and is the
4146
default value.
4247

48+
mergetool.hideResolved::
49+
During a merge Git will automatically resolve as many conflicts as
50+
possible and write the 'MERGED' file containing conflict markers around
51+
any conflicts that it cannot resolve; 'LOCAL' and 'REMOTE' normally
52+
represent the versions of the file from before Git's conflict
53+
resolution. This flag causes 'LOCAL' and 'REMOTE' to be overwriten so
54+
that only the unresolved conflicts are presented to the merge tool. Can
55+
be configured per-tool via the `mergetool.<tool>.hideResolved`
56+
configuration variable. Defaults to `true`.
57+
4358
mergetool.keepBackup::
4459
After performing a merge, the original file with conflict markers
4560
can be saved as a file with a `.orig` extension. If this variable

Documentation/git-mergetool--lib.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ get_merge_tool_cmd::
3838
get_merge_tool_path::
3939
returns the custom path for a merge tool.
4040

41+
initialize_merge_tool::
42+
bring merge tool specific functions into scope so they can be used or
43+
overridden.
44+
4145
run_merge_tool::
4246
launches a merge tool given the tool name and a true/false
4347
flag to indicate whether a merge base is present.

git-difftool--helper.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,9 @@ launch_merge_tool () {
6161
export BASE
6262
eval $GIT_DIFFTOOL_EXTCMD '"$LOCAL"' '"$REMOTE"'
6363
else
64+
initialize_merge_tool "$merge_tool"
65+
# ignore the error from the above --- run_merge_tool
66+
# will diagnose unusable tool by itself
6467
run_merge_tool "$merge_tool"
6568
fi
6669
}
@@ -79,6 +82,9 @@ if test -n "$GIT_DIFFTOOL_DIRDIFF"
7982
then
8083
LOCAL="$1"
8184
REMOTE="$2"
85+
initialize_merge_tool "$merge_tool"
86+
# ignore the error from the above --- run_merge_tool
87+
# will diagnose unusable tool by itself
8288
run_merge_tool "$merge_tool" false
8389
else
8490
# Launch the merge tool on each path provided by 'git diff'

git-mergetool--lib.sh

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,10 @@ setup_tool () {
166166
return 1
167167
}
168168

169+
hide_resolved_enabled () {
170+
return 0
171+
}
172+
169173
translate_merge_tool_path () {
170174
echo "$1"
171175
}
@@ -250,6 +254,10 @@ trust_exit_code () {
250254
fi
251255
}
252256

257+
initialize_merge_tool () {
258+
# Bring tool-specific functions into scope
259+
setup_tool "$1" || return 1
260+
}
253261

254262
# Entry point for running tools
255263
run_merge_tool () {
@@ -261,9 +269,6 @@ run_merge_tool () {
261269
merge_tool_path=$(get_merge_tool_path "$1") || exit
262270
base_present="$2"
263271

264-
# Bring tool-specific functions into scope
265-
setup_tool "$1" || return 1
266-
267272
if merge_mode
268273
then
269274
run_merge_cmd "$1"

git-mergetool.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@ checkout_staged_file () {
239239
fi
240240
}
241241

242+
hide_resolved () {
243+
git merge-file --ours -q -p "$LOCAL" "$BASE" "$REMOTE" >"$LCONFL"
244+
git merge-file --theirs -q -p "$LOCAL" "$BASE" "$REMOTE" >"$RCONFL"
245+
mv -- "$LCONFL" "$LOCAL"
246+
mv -- "$RCONFL" "$REMOTE"
247+
}
248+
242249
merge_file () {
243250
MERGED="$1"
244251

@@ -265,6 +272,8 @@ merge_file () {
265272
ext=
266273
esac
267274

275+
initialize_merge_tool "$merge_tool" || return
276+
268277
mergetool_tmpdir_init
269278

270279
if test "$MERGETOOL_TMPDIR" != "."
@@ -276,7 +285,9 @@ merge_file () {
276285

277286
BACKUP="$MERGETOOL_TMPDIR/${BASE}_BACKUP_$$$ext"
278287
LOCAL="$MERGETOOL_TMPDIR/${BASE}_LOCAL_$$$ext"
288+
LCONFL="$MERGETOOL_TMPDIR/${BASE}_LOCAL_LCONFL_$$$ext"
279289
REMOTE="$MERGETOOL_TMPDIR/${BASE}_REMOTE_$$$ext"
290+
RCONFL="$MERGETOOL_TMPDIR/${BASE}_REMOTE_RCONFL_$$$ext"
280291
BASE="$MERGETOOL_TMPDIR/${BASE}_BASE_$$$ext"
281292

282293
base_mode= local_mode= remote_mode=
@@ -322,6 +333,45 @@ merge_file () {
322333
checkout_staged_file 2 "$MERGED" "$LOCAL"
323334
checkout_staged_file 3 "$MERGED" "$REMOTE"
324335

336+
# hideResolved preferences hierarchy.
337+
global_config="mergetool.hideResolved"
338+
tool_config="mergetool.${merge_tool}.hideResolved"
339+
340+
if enabled=$(git config --type=bool "$tool_config")
341+
then
342+
# The user has a specific preference for a specific tool and no
343+
# other preferences should override that.
344+
: ;
345+
elif enabled=$(git config --type=bool "$global_config")
346+
then
347+
# The user has a general preference for all tools.
348+
#
349+
# 'true' means the user likes the feature so we should use it
350+
# where possible but tool authors can still override.
351+
#
352+
# 'false' means the user doesn't like the feature so we should
353+
# not use it anywhere.
354+
if test "$enabled" = true && hide_resolved_enabled
355+
then
356+
enabled=true
357+
else
358+
enabled=false
359+
fi
360+
else
361+
# The user does not have a preference. Ask the tool.
362+
if hide_resolved_enabled
363+
then
364+
enabled=true
365+
else
366+
enabled=false
367+
fi
368+
fi
369+
370+
if test "$enabled" = true
371+
then
372+
hide_resolved
373+
fi
374+
325375
if test -z "$local_mode" || test -z "$remote_mode"
326376
then
327377
echo "Deleted merge conflict for '$MERGED':"

t/t7610-mergetool.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,4 +842,22 @@ test_expect_success 'mergetool --tool-help shows recognized tools' '
842842
grep meld mergetools
843843
'
844844

845+
test_expect_success 'mergetool hideResolved' '
846+
test_config mergetool.hideResolved true &&
847+
test_when_finished "git reset --hard" &&
848+
git checkout -b test${test_count}_b main &&
849+
test_write_lines >file1 base "" a &&
850+
git commit -a -m "base" &&
851+
test_write_lines >file1 base "" c &&
852+
git commit -a -m "remote update" &&
853+
git checkout -b test${test_count}_a HEAD~ &&
854+
test_write_lines >file1 local "" b &&
855+
git commit -a -m "local update" &&
856+
test_must_fail git merge test${test_count}_b &&
857+
yes "" | git mergetool file1 &&
858+
test_write_lines >expect local "" c &&
859+
test_cmp expect file1 &&
860+
git commit -m "test resolved with mergetool"
861+
'
862+
845863
test_done

0 commit comments

Comments
 (0)