The goal of the patch is to introduce the GNU diff -B/--ignore-blank-lines as closely as possible. The short option is not available because it's already used for "break-rewrites". When this option is used, git-diff will not create hunks that simply adds or removes empty lines, but will still show empty lines addition/suppression if they are close enough to "valuable" changes. Signed-off-by: Antoine Pelisse <apelisse@xxxxxxxxx> --- Documentation/diff-options.txt | 3 ++ diff.c | 2 ++ t/t4015-diff-whitespace.sh | 65 ++++++++++++++++++++++++++++++++++++++++ xdiff/xdiff.h | 2 ++ xdiff/xdiffi.c | 29 +++++++++++++++++- xdiff/xdiffi.h | 1 + xdiff/xemit.c | 32 ++++++++++++++++---- xdiff/xemit.h | 2 +- xdiff/xutils.c | 13 ++++++++ xdiff/xutils.h | 1 + 10 files changed, 143 insertions(+), 7 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 104579d..80f06b7 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -439,6 +439,9 @@ endif::git-format-patch[] differences even if one line has whitespace where the other line has none. +--ignore-blank-lines:: + Ignore changes whose lines are all blank. + --inter-hunk-context=<lines>:: Show the context between diff hunks, up to the specified number of lines, thereby fusing hunks that are close to each other. diff --git a/diff.c b/diff.c index f0b3e7c..208094f 100644 --- a/diff.c +++ b/diff.c @@ -3593,6 +3593,8 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac) DIFF_XDL_SET(options, IGNORE_WHITESPACE_CHANGE); else if (!strcmp(arg, "--ignore-space-at-eol")) DIFF_XDL_SET(options, IGNORE_WHITESPACE_AT_EOL); + else if (!strcmp(arg, "--ignore-blank-lines")) + DIFF_XDL_SET(options, IGNORE_BLANK_LINES); else if (!strcmp(arg, "--patience")) options->xdl_opts = DIFF_WITH_ALG(options, PATIENCE_DIFF); else if (!strcmp(arg, "--histogram")) diff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh index cc3db13..b3c4fcc 100755 --- a/t/t4015-diff-whitespace.sh +++ b/t/t4015-diff-whitespace.sh @@ -142,6 +142,71 @@ EOF git diff --ignore-space-at-eol > out test_expect_success 'another test, with --ignore-space-at-eol' 'test_cmp expect out' +test_expect_success 'ignore-blank-lines: only new lines' ' + seq 5 >x && + git update-index x && + seq 5 | sed "/3/i \\\\" >x && + git diff --ignore-blank-lines >out && + printf "" >expect && + test_cmp out expect +' + +test_expect_success 'ignore-blank-lines: only new lines with space' ' + seq 5 >x && + git update-index x && + seq 5 | sed "/3/i \ " >x && + git diff -w --ignore-blank-lines >out && + printf "" >expect && + test_cmp out expect +' + + +test_expect_success 'ignore-blank-lines: with changes' ' + seq 11 >x && + git update-index x && + cat <<-\EOF >x && + + 1 + 2 + 3 + change + 4 + 5 + 6 + 7 + + 8 + change + 9 + 10 + 11 + + EOF + git diff --ignore-blank-lines >out.tmp && + sed -e "1,/^+++ b\/x/d" <out.tmp >out && + cat <<-\EOF >expect && + @@ -1,6 +2,7 @@ + 1 + 2 + 3 + +change + 4 + 5 + 6 + @@ -5,7 +7,9 @@ + 5 + 6 + 7 + + + 8 + +change + 9 + 10 + 11 + EOF + test_cmp out expect +' + test_expect_success 'check mixed spaces and tabs in indent' ' # This is indented with SP HT SP. diff --git a/xdiff/xdiff.h b/xdiff/xdiff.h index 219a3bb..c033991 100644 --- a/xdiff/xdiff.h +++ b/xdiff/xdiff.h @@ -39,6 +39,8 @@ extern "C" { #define XDF_DIFF_ALGORITHM_MASK (XDF_PATIENCE_DIFF | XDF_HISTOGRAM_DIFF) #define XDF_DIFF_ALG(x) ((x) & XDF_DIFF_ALGORITHM_MASK) +#define XDF_IGNORE_BLANK_LINES (1 << 7) + #define XDL_EMIT_FUNCNAMES (1 << 0) #define XDL_EMIT_COMMON (1 << 1) #define XDL_EMIT_FUNCCONTEXT (1 << 2) diff --git a/xdiff/xdiffi.c b/xdiff/xdiffi.c index b2eb6db..3cabc78 100644 --- a/xdiff/xdiffi.c +++ b/xdiff/xdiffi.c @@ -394,6 +394,7 @@ static xdchange_t *xdl_add_change(xdchange_t *xscr, long i1, long i2, long chg1, xch->i2 = i2; xch->chg1 = chg1; xch->chg2 = chg2; + xch->ignore = 0; return xch; } @@ -544,7 +545,9 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdchange_t *xch, *xche; for (xch = xscr; xch; xch = xche->next) { - xche = xdl_get_hunk(xch, xecfg); + xche = xdl_get_hunk(&xch, xecfg); + if (!xch) + break; if (xecfg->hunk_func(xch->i1, xche->i1 + xche->chg1 - xch->i1, xch->i2, xche->i2 + xche->chg2 - xch->i2, ecb->priv) < 0) @@ -553,6 +556,27 @@ static int xdl_call_hunk_func(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, return 0; } +static void xdl_mark_ignorable(xdchange_t *xscr, xdfenv_t *xe, long flags) +{ + xdchange_t *xch; + + for (xch = xscr; xch; xch = xch->next) { + int ignore = 1; + xrecord_t **rec; + long i; + + rec = &xe->xdf1.recs[xch->i1]; + for (i = 0; i < xch->chg1 && ignore; i++) + ignore = xdl_blankline(rec[i]->ptr, flags); + + rec = &xe->xdf2.recs[xch->i2]; + for (i = 0; i < xch->chg2 && ignore; i++) + ignore = xdl_blankline(rec[i]->ptr, flags); + + xch->ignore = ignore; + } +} + int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, xdemitconf_t const *xecfg, xdemitcb_t *ecb) { xdchange_t *xscr; @@ -571,6 +595,9 @@ int xdl_diff(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp, return -1; } if (xscr) { + if (xpp->flags & XDF_IGNORE_BLANK_LINES) + xdl_mark_ignorable(xscr, &xe, xpp->flags); + if (ef(&xe, xscr, ecb, xecfg) < 0) { xdl_free_script(xscr); diff --git a/xdiff/xdiffi.h b/xdiff/xdiffi.h index 7a92ea9..8b81206 100644 --- a/xdiff/xdiffi.h +++ b/xdiff/xdiffi.h @@ -41,6 +41,7 @@ typedef struct s_xdchange { struct s_xdchange *next; long i1, i2; long chg1, chg2; + int ignore; } xdchange_t; diff --git a/xdiff/xemit.c b/xdiff/xemit.c index d11dbf9..52dfef8 100644 --- a/xdiff/xemit.c +++ b/xdiff/xemit.c @@ -56,14 +56,34 @@ static int xdl_emit_record(xdfile_t *xdf, long ri, char const *pre, xdemitcb_t * /* * Starting at the passed change atom, find the latest change atom to be included * inside the differential hunk according to the specified configuration. + * Also advance xscr if the first changes must be discareded. */ -xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg) { +xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg) { xdchange_t *xch, *xchp; long max_common = 2 * xecfg->ctxlen + xecfg->interhunkctxlen; + long ignorable_context = max_common / 2 - 1; + int interesting = 0; - for (xchp = xscr, xch = xscr->next; xch; xchp = xch, xch = xch->next) - if (xch->i1 - (xchp->i1 + xchp->chg1) > max_common) - break; + for (xchp = *xscr, xch = (*xscr)->next; xch; xchp = xch, xch = xch->next) { + long thresh; + if (xchp->ignore || xch->ignore) + thresh = ignorable_context; + else + thresh = max_common; + + if (!xchp->ignore) + interesting = 1; + + if (xch->i1 - (xchp->i1 + xchp->chg1) > thresh) { + if (interesting) + break; + else + *xscr = xch; + } + } + + if (!interesting && xchp->ignore) + *xscr = NULL; return xchp; } @@ -139,7 +159,9 @@ int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, return xdl_emit_common(xe, xscr, ecb, xecfg); for (xch = xscr; xch; xch = xche->next) { - xche = xdl_get_hunk(xch, xecfg); + xche = xdl_get_hunk(&xch, xecfg); + if (!xch) + break; s1 = XDL_MAX(xch->i1 - xecfg->ctxlen, 0); s2 = XDL_MAX(xch->i2 - xecfg->ctxlen, 0); diff --git a/xdiff/xemit.h b/xdiff/xemit.h index c2e2e83..d297107 100644 --- a/xdiff/xemit.h +++ b/xdiff/xemit.h @@ -27,7 +27,7 @@ typedef int (*emit_func_t)(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); -xdchange_t *xdl_get_hunk(xdchange_t *xscr, xdemitconf_t const *xecfg); +xdchange_t *xdl_get_hunk(xdchange_t **xscr, xdemitconf_t const *xecfg); int xdl_emit_diff(xdfenv_t *xe, xdchange_t *xscr, xdemitcb_t *ecb, xdemitconf_t const *xecfg); diff --git a/xdiff/xutils.c b/xdiff/xutils.c index 9504eae..c047376 100644 --- a/xdiff/xutils.c +++ b/xdiff/xutils.c @@ -143,6 +143,19 @@ long xdl_guess_lines(mmfile_t *mf, long sample) { return nl + 1; } +int xdl_blankline(const char *line, long flags) +{ + long i; + + if (!(flags & XDF_WHITESPACE_FLAGS)) + return (*line == '\n'); + + for (i = 0; line[i] != '\n' && XDL_ISSPACE(line[i]); i++) + ; + + return (line[i] == '\n'); +} + int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags) { int i1, i2; diff --git a/xdiff/xutils.h b/xdiff/xutils.h index ad1428e..b9cceff 100644 --- a/xdiff/xutils.h +++ b/xdiff/xutils.h @@ -32,6 +32,7 @@ int xdl_cha_init(chastore_t *cha, long isize, long icount); void xdl_cha_free(chastore_t *cha); void *xdl_cha_alloc(chastore_t *cha); long xdl_guess_lines(mmfile_t *mf, long sample); +int xdl_blankline(const char *line, long flags); int xdl_recmatch(const char *l1, long s1, const char *l2, long s2, long flags); unsigned long xdl_hash_record(char const **data, char const *top, long flags); unsigned int xdl_hashbits(unsigned int size); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html