Reputation: 24794
We can use git
's diff tool without git repos with git diff --no-index <FILE-A> <FILE-B>
.
Is there a similar command for running git
's merge algorithm given three input files ("ours", base & "theirs")? And specifically it should output the "diff3" style (seeing the "base" in the conflict is essential)
I understand that it couldn't be as smart as git's recursive merge strategy but I would be very satisfied with something basic like the "resolve" strategy.
Upvotes: 3
Views: 325
Reputation: 1327204
running git's merge algorithm
There are actually more than one merge result, depending on the diff algorithm used: myers, minimal, patience, and histogram.
See "When to Use Each of the Git Diff Algorithms" by Lup Peng Loke, for details on those.
As mentioned in jthill's answer, you can use git merge-file
:
git merge-file -p --diff3 ours base theirs
With Git 2.44 (Q1 2024), "git merge-file
"(man) learned to take the --diff-algorithm
option to use an algorithm different from the default myers diff.
See commit 4f7fd79 (20 Nov 2023) by Antonin Delpeuch (wetneb
).
(Merged by Junio C Hamano -- gitster
-- in commit 7895686, 18 Dec 2023)
merge-file
: add --diff-algorithm optionSigned-off-by: Antonin Delpeuch
Reviewed-by: Phillip Wood
Make it possible to use other diff algorithms than the 'myers' default algorithm, when using the '
git merge-file
'(man) command, to help avoid spurious conflicts by selecting a more recent algorithm such as 'histogram', for instance when using 'git merge-file
' as part of a custom merge driver.
git merge-file
now includes in its man page:
--diff-algorithm={patience|minimal|histogram|myers}
Use a different diff algorithm while merging.
The current default is "myers", but selecting more recent algorithm such as "histogram" can help avoid mismerges that occur due to unimportant matching lines (such as braces from distinct functions).
See also
git diff --diff-algorithm
.
So now:
git merge-file -p --diff-algorithm={patience|minimal|histogram|myers} --diff3 ours base theirs
"git diff --no-index file1 file2
"(man) segfaulted while invoking the external diff driver, which has been corrected with Git 2.44 (Q1 2024), batch 14.
See commit 85a9a63 (28 Jan 2024) by Jeff King (peff
).
(Merged by Junio C Hamano -- gitster
-- in commit 92e69df, 06 Feb 2024)
diff
: handle NULL meta-info when spawning external diffReported-by: Wilfred Hughes
Signed-off-by: Jeff King
Running this:
$ touch foo bar $ chmod +x foo $ git -c diff.external=echo diff --ext-diff --no-index foo bar
results in a segfault.
The issue is that
run_diff_cmd()
passes aNULL
"xfrm_msg"
variable torun_external_diff()
, which feeds it tostrvec_push()
, causing the segfault.The bug dates back to 82fbf26 (
run_external_diff
: use an argv_array for the command line, 2014-04-19, Git v2.0.0-rc2 -- merge)(run_external_diff
: use anargv_array
for the command line, 2014-04-19), though it mostly only ever worked accidentally.
Before then, we just stuck theNULL
pointer into a "const char **" array, so ourNULL
ended up acting as an extra end-of-argv sentinel (which was OK, because it was the last thing in the array).Curiously, though, this is only a problem with
--no-index
.
We set upxfrm_msg
by callingfill_metainfo()
.
This result may be empty, or may have text like "index 1234..5678\n", "rename from foo\nrename from bar\n", etc.
Inrun_external_diff()
, we only look atxfrm_msg
if the "other" variable is notNULL
.
That variable is set when the paths of the two sides of the diff pair aren't the same (in which case the destination path becomes "other").
So normally it would kick in only for a rename, in which casexfrm_msg
should not beNULL
(it would have the rename information in it).But with a "
--no-index
" of two blobs, we of course have two different pathnames, and thus end up with a non-NULL "other" filename (which is always just a repeat of the file2-name), but possibly aNULL xfrm_msg
.So how to fix it? I have a feeling that
--no-index
always passing other to the external diff command is probably a bug.
There was no rename, and the name is always redundant with existing information we pass (and this may even cause us to pass a useless"xfrm_msg"
that contains an "index 1234..5678
" line).
So one option would be to change that behavior.
We don't seem to have ever documented the "other" or"xfrm_msg"
parameters for external diffs.But I'm not sure what fallout we might have from changing that behavior now.
So this patch takes the less-risky option, and simply teachesrun_external_diff()
to avoid passingxfrm_msg
when it'sNULL
.
That makes it agnostic to whether "other" and"xfrm_msg"
always come as a pair.
It fixes the segfault now, and if we want to change the--no-index
other behavior on top, it will handle that, too.
Upvotes: 1