Skip to content

Commit 98ea309

Browse files
whiteingegitster
authored andcommitted
mergetool: add hideResolved configuration
The purpose of a mergetool is to help the user resolve any conflicts that Git cannot automatically resolve. If there is a conflict that must be resolved manually Git will write a file named MERGED which contains everything Git was able to resolve by itself and also everything that it was not able to resolve wrapped in conflict markers. One way to think of MERGED is as a two- or three-way diff. If each "side" of the conflict markers is separately extracted an external tool can represent those conflicts as a side-by-side diff. However many mergetools instead diff LOCAL and REMOTE both of which contain versions of the file from before the merge. Since the conflicts Git resolved automatically are not present it forces the user to manually re-resolve those conflicts. Some mergetools also show MERGED but often only for reference and not as the focal point to resolve the conflicts. This adds a `mergetool.hideResolved` flag that will overwrite LOCAL and REMOTE with each corresponding "side" of a conflicted file and thus hide all conflicts that Git was able to resolve itself. Overwriting these files will immediately benefit any mergetool that uses them without requiring any changes to the tool. No adverse effects were noted in a small survey of popular mergetools[1] so this behavior defaults to `true`. However it can be globally disabled by setting `mergetool.hideResolved` to `false`. [1] https://www.eseth.org/2020/mergetools.html https://github.com/whiteinge/eseth/blob/c884424769fffb05d87afb33b2cf80cecb4044c3/2020/mergetools.md Original-implementation-by: Felipe Contreras <[email protected]> Signed-off-by: Seth House <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6d3ef5b commit 98ea309

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

Documentation/config/mergetool.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ mergetool.meld.useAutoMerge::
4040
value of `false` avoids using `--auto-merge` altogether, and is the
4141
default value.
4242

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

git-mergetool.sh

Lines changed: 14 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

@@ -276,7 +283,9 @@ merge_file () {
276283

277284
BACKUP="$MERGETOOL_TMPDIR/${BASE}_BACKUP_$$$ext"
278285
LOCAL="$MERGETOOL_TMPDIR/${BASE}_LOCAL_$$$ext"
286+
LCONFL="$MERGETOOL_TMPDIR/${BASE}_LOCAL_LCONFL_$$$ext"
279287
REMOTE="$MERGETOOL_TMPDIR/${BASE}_REMOTE_$$$ext"
288+
RCONFL="$MERGETOOL_TMPDIR/${BASE}_REMOTE_RCONFL_$$$ext"
280289
BASE="$MERGETOOL_TMPDIR/${BASE}_BASE_$$$ext"
281290

282291
base_mode= local_mode= remote_mode=
@@ -322,6 +331,11 @@ merge_file () {
322331
checkout_staged_file 2 "$MERGED" "$LOCAL"
323332
checkout_staged_file 3 "$MERGED" "$REMOTE"
324333

334+
if test "$(git config --type=bool mergetool.hideResolved)" != "false"
335+
then
336+
hide_resolved
337+
fi
338+
325339
if test -z "$local_mode" || test -z "$remote_mode"
326340
then
327341
echo "Deleted merge conflict for '$MERGED':"

t/t7610-mergetool.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,4 +828,22 @@ test_expect_success 'mergetool -Oorder-file is honored' '
828828
test_cmp expect actual
829829
'
830830

831+
test_expect_success 'mergetool hideResolved' '
832+
test_config mergetool.hideResolved true &&
833+
test_when_finished "git reset --hard" &&
834+
git checkout -b test${test_count}_b master &&
835+
test_write_lines >file1 base "" a &&
836+
git commit -a -m "base" &&
837+
test_write_lines >file1 base "" c &&
838+
git commit -a -m "remote update" &&
839+
git checkout -b test${test_count}_a HEAD~ &&
840+
test_write_lines >file1 local "" b &&
841+
git commit -a -m "local update" &&
842+
test_must_fail git merge test${test_count}_b &&
843+
yes "" | git mergetool file1 &&
844+
test_write_lines >expect local "" c &&
845+
test_cmp expect file1 &&
846+
git commit -m "test resolved with mergetool"
847+
'
848+
831849
test_done

0 commit comments

Comments
 (0)