diff options
| author | Junio C Hamano <gitster@pobox.com> | 2026-03-24 12:31:34 -0700 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-03-24 12:31:34 -0700 |
| commit | 231f8100c41fdbdd49f5bca953fff775a79321db (patch) | |
| tree | a81cdbda22a176f4fe47505ed1e1956d94f4ac5d /xdiff | |
| parent | 7f13e5c8c744ec8da268b6f774d16f2ea729f48e (diff) | |
| parent | e417277ae99687b576e48cb477a7a50241ea0096 (diff) | |
| download | git-231f8100c41fdbdd49f5bca953fff775a79321db.tar.xz | |
Merge branch 'yc/histogram-hunk-shift-fix'
The final clean-up phase of the diff output could turn the result of
histogram diff algorithm suboptimal, which has been corrected.
* yc/histogram-hunk-shift-fix:
xdiff: re-diff shifted change groups when using histogram algorithm
Diffstat (limited to 'xdiff')
| -rw-r--r-- | xdiff/xdiffi.c | 47 |
1 files changed, 45 insertions, 2 deletions
diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index 4376f943db..5455b4690d 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -792,6 +792,7 @@ static int group_slide_up(xdfile_t *xdf, struct xdlgroup *g) */ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { struct xdlgroup g, go; + struct xdlgroup g_orig; long earliest_end, end_matching_other; long groupsize; @@ -805,10 +806,12 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { if (g.end == g.start) goto next; + g_orig = g; + /* * Now shift the change up and then down as far as possible in * each direction. If it bumps into any other changes, merge - * them. + * them and restart the process. */ do { groupsize = g.end - g.start; @@ -861,7 +864,8 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { /* * Move the possibly merged group of changes back to * line up with the last group of changes from the - * other file that it can align with. + * other file that it can align with. This avoids breaking + * a single change into a separate addition/deletion. */ while (go.end == go.start) { if (group_slide_up(xdf, &g)) @@ -914,6 +918,45 @@ int xdl_change_compact(xdfile_t *xdf, xdfile_t *xdfo, long flags) { } } + /* + * If we merged change groups during shifting, the new + * combined group could now have matching lines in both files, + * even if the original separate groups did not. Re-diff the + * new group to find these matching lines to mark them as + * unchanged. + * + * Only do this if the corresponding group in the other file is + * non-empty, as it's trivial otherwise. + * + * Only do this for histogram diff as its LCS algorithm allows + * for this scenario. In contrast, patience diff finds LCS + * of unique lines that groups cannot be shifted across. + * Myer's diff (standalone or used as fall-back in patience + * diff) already finds minimal edits so it is not possible for + * shifted groups to result in a smaller diff. (Without + * XDF_NEED_MINIMAL, Myer's isn't technically guaranteed to be + * minimal, but it should be so most of the time) + */ + if (go.end != go.start && + XDF_DIFF_ALG(flags) == XDF_HISTOGRAM_DIFF && + (g.start != g_orig.start || + g.end != g_orig.end)) { + xpparam_t xpp; + xdfenv_t xe; + + memset(&xpp, 0, sizeof(xpp)); + xpp.flags = flags & ~XDF_DIFF_ALGORITHM_MASK; + + xe.xdf1 = *xdf; + xe.xdf2 = *xdfo; + + if (xdl_fall_back_diff(&xe, &xpp, + g.start + 1, g.end - g.start, + go.start + 1, go.end - go.start)) { + return -1; + } + } + next: /* Move past the just-processed group: */ if (group_next(xdf, &g)) |
