From: Ævar Arnfjörð Bjarmason Date: Wed, 24 Apr 2019 15:22:15 GMT Subject: [PATCH 2/2] diffcore-pickaxe: add --pickaxe-raw-diff for use with -G Message-ID: <20190424152215.16251-3-avarab@gmail.com> In-Reply-To: <20190424102609.GA19697@vmlxhi-102.adit-jv.com> Add the ability for the -G pickaxe to search only through added or removed lines in the diff, or even through an arbitrary amount of context lines when combined with -U. This has been requested[1][2] a few times in the past, and isn't currently possible. Instead users need to do -G and then write their own post-parsing script to see if the matched added or removed lines, or both. There was no way to match the adjacent context lines other than running and grepping the equivalent of a "log -p -U". 1. https://public-inbox.org/git/xmqqwoqrr8y2.fsf@gitster-ct.c.googlers.com/ 2. https://public-inbox.org/git/20190424102609.GA19697@vmlxhi-102.adit-jv.com/ Signed-off-by: Ævar Arnfjörð Bjarmason --- Documentation/diff-options.txt | 17 +++++++++++++ diff.c | 3 +++ diff.h | 2 ++ diffcore-pickaxe.c | 34 ++++++++++++++++++++++--- t/t4013-diff-various.sh | 1 + t/t4209-log-pickaxe.sh | 45 ++++++++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 4 deletions(-) diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt index 09faee3b44..f367b40362 100644 --- a/Documentation/diff-options.txt +++ b/Documentation/diff-options.txt @@ -579,6 +579,9 @@ occurrences of that string did not change). Unless `--text` is supplied patches of binary files without a textconv filter will be ignored. + +When `--pickaxe-raw-diff` is supplied the whole diff is searched +instead of just added/removed lines. See below. ++ See the 'pickaxe' entry in linkgit:gitdiffcore[7] for more information. @@ -600,6 +603,20 @@ The object can be a blob or a submodule commit. It implies the `-t` option in Treat the given to `-S` as an extended POSIX regular expression to match. +--pickaxe-raw-diff:: + When `-G` looks for a change a diff will be generated, and + only the added/removed lines will be matched against with the + "+" or "-" stripped. ++ +Supplying this option skips that pre-processing. This makes it +possible to match only lines that added or removed something matching +a with "\^\+" and "^-", respectively. ++ +It also allows for finding something in the diff context. E.g. "\^ +" will match the context lines (see `-U` above) around the +added/removed lines, and doing an unanchored match will match any of +the the added/removed lines & diff context. + endif::git-format-patch[] -O:: diff --git a/diff.c b/diff.c index 4d3cf83a27..4cdc000ee5 100644 --- a/diff.c +++ b/diff.c @@ -5503,6 +5503,9 @@ static void prep_parse_options(struct diff_options *options) OPT_BIT_F(0, "pickaxe-regex", &options->pickaxe_opts, N_("treat in -S as extended POSIX regular expression"), DIFF_PICKAXE_REGEX, PARSE_OPT_NONEG), + OPT_BIT_F(0, "pickaxe-raw-diff", &options->pickaxe_opts, + N_("have in -G match the raw diff output"), + DIFF_PICKAXE_G_RAW_DIFF, PARSE_OPT_NONEG), OPT_FILENAME('O', NULL, &options->orderfile, N_("control the order in which files appear in the output")), OPT_CALLBACK_F(0, "find-object", options, N_(""), diff --git a/diff.h b/diff.h index b20cbcc091..d431fbc602 100644 --- a/diff.h +++ b/diff.h @@ -370,6 +370,8 @@ int git_config_rename(const char *var, const char *value); DIFF_PICKAXE_KIND_OBJFIND) #define DIFF_PICKAXE_IGNORE_CASE 32 +#define DIFF_PICKAXE_G_RAW_DIFF 64 + void diffcore_std(struct diff_options *); void diffcore_fix_diff_index(void); diff --git a/diffcore-pickaxe.c b/diffcore-pickaxe.c index 3c6416bfe2..e23f04b4f0 100644 --- a/diffcore-pickaxe.c +++ b/diffcore-pickaxe.c @@ -17,14 +17,18 @@ typedef int (*pickaxe_fn)(mmfile_t *one, mmfile_t *two, struct diffgrep_cb { regex_t *regexp; int hit; + int raw_diff; }; static void diffgrep_consume(void *priv, char *line, unsigned long len) { struct diffgrep_cb *data = priv; regmatch_t regmatch; + int raw_diff = data->raw_diff; + const char *string = raw_diff ? line : line + 1; + size_t size = raw_diff ? len : len - 1; - if (line[0] != '+' && line[0] != '-') + if (!raw_diff && line[0] != '+' && line[0] != '-') return; if (data->hit) /* @@ -32,7 +36,7 @@ static void diffgrep_consume(void *priv, char *line, unsigned long len) * caller early. */ return; - data->hit = !regexec_buf(data->regexp, line + 1, len - 1, 1, + data->hit = !regexec_buf(data->regexp, string, size, 1, ®match, 0); } @@ -44,15 +48,36 @@ static int diff_grep(mmfile_t *one, mmfile_t *two, struct diffgrep_cb ecbdata; xpparam_t xpp; xdemitconf_t xecfg; + int raw_diff = o->pickaxe_opts & DIFF_PICKAXE_G_RAW_DIFF; + struct strbuf sb = STRBUF_INIT; + char *string; + size_t size; if (!one || !two) { mmfile_t *which = one ? one : two; int ret; - char *string = which->ptr; - size_t size = which->size; assert(!(!one && !two)); + if (raw_diff) { + /* + * When we have created/deleted files with + * --pickaxe-raw-diff we need to fake up the + * "+" and "-" at the start of the lines, a + * plain -G without --pickaxe-raw-diff didn't + * care since it would indiscriminately search + * through both added and removed lines. + */ + strbuf_add_lines(&sb, !one ? "+" : "-", which->ptr, + which->size); + string = sb.buf; + size = sb.len; + } else { + string = which->ptr; + size = which->size; + } ret = !regexec_buf(regexp, string, size, 1, ®match, 0); + if (raw_diff) + strbuf_release(&sb); return ret; } @@ -64,6 +89,7 @@ static int diff_grep(mmfile_t *one, mmfile_t *two, memset(&xecfg, 0, sizeof(xecfg)); ecbdata.regexp = regexp; ecbdata.hit = 0; + ecbdata.raw_diff = raw_diff; xecfg.ctxlen = o->context; xecfg.interhunkctxlen = o->interhunkcontext; if (xdi_diff_outf(one, two, discard_hunk_line, diffgrep_consume, diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh index 9f8f0e84ad..39a1f6c230 100755 --- a/t/t4013-diff-various.sh +++ b/t/t4013-diff-various.sh @@ -276,6 +276,7 @@ log -SF master --max-count=1 log -SF master --max-count=2 log -GF master log -GF -p master +log -GF -p --pickaxe-raw-diff master log -GF -p --pickaxe-all master log --decorate --all log --decorate=full --all diff --git a/t/t4209-log-pickaxe.sh b/t/t4209-log-pickaxe.sh index 5d06f5f45e..2d98318d23 100755 --- a/t/t4209-log-pickaxe.sh +++ b/t/t4209-log-pickaxe.sh @@ -141,4 +141,49 @@ test_expect_success 'log -S looks into binary files' ' test_cmp log full-log ' +test_expect_success 'setup log -G --pickaxe-raw-diff' ' + git checkout --orphan G-raw-diff && + test_write_lines A B C D E F G >file && + git add file && + git commit --allow-empty-message file && + sed -i -e "s/B/2/" file && + git add file && + git commit --allow-empty-message file && + sed -i -e "s/D/4/" file && + git add file && + git commit --allow-empty-message file && + git rm file && + git commit --allow-empty-message && + git log --oneline -1 HEAD~0 >file.fourth && + git log --oneline -1 HEAD~1 >file.third && + git log --oneline -1 HEAD~2 >file.second && + git log --oneline -1 HEAD~3 >file.first +' + +test_expect_success 'log -G --pickaxe-raw-diff skips header and range information' ' + git log --pickaxe-raw-diff -p -G"(@@|file)" >log && + test_must_be_empty log +' + +test_expect_success 'log -G --pickaxe-raw-diff searching in context' ' + git log --oneline --pickaxe-raw-diff -G"^ F" -U2 -s >log && + test_cmp file.third log && + git log --oneline --pickaxe-raw-diff -G"^ F" -U1 -s >log && + test_must_be_empty log +' + +test_expect_success 'log -G --pickaxe-raw-diff searching added / removed lines (skip create/delete)' ' + git log --oneline --pickaxe-raw-diff -G"^-[D2]" -s HEAD~1 >log && + test_cmp file.third log && + git log --oneline --pickaxe-raw-diff -G"^\+[D2]" -s -1 >log && + test_cmp file.second log +' + +test_expect_success 'log -G --pickaxe-raw-diff searching created / deleted files' ' + git log --oneline --pickaxe-raw-diff -G"^\+A" -s >log && + test_cmp file.first log && + git log --oneline --pickaxe-raw-diff -G"^\-A" -s >log && + test_cmp file.fourth log +' + test_done -- 2.21.0.593.g511ec345e18