Merge branch 'jc/pickaxe-grep'

* jc/pickaxe-grep:
  diff/log -G<pattern>: tests
  git log/diff: add -G<regexp> that greps in the patch text
  diff: pass the entire diff-options to diffcore_pickaxe()
  gitdiffcore doc: update pickaxe description
This commit is contained in:
Junio C Hamano 2010-09-29 13:49:03 -07:00
commit b3c16ee454
10 changed files with 226 additions and 9 deletions

View file

@ -284,8 +284,12 @@ ifndef::git-format-patch[]
appearing in diff output; see the 'pickaxe' entry in appearing in diff output; see the 'pickaxe' entry in
linkgit:gitdiffcore[7] for more details. linkgit:gitdiffcore[7] for more details.
-G<regex>::
Look for differences whose added or removed line matches
the given <regex>.
--pickaxe-all:: --pickaxe-all::
When `-S` finds a change, show all the changes in that When `-S` or `-G` finds a change, show all the changes in that
changeset, not just the files that contain the change changeset, not just the files that contain the change
in <string>. in <string>.

View file

@ -227,9 +227,9 @@ changes that touch a specified string, and is controlled by the
commands. commands.
When diffcore-pickaxe is in use, it checks if there are When diffcore-pickaxe is in use, it checks if there are
filepairs whose "result" side has the specified string and filepairs whose "result" side and whose "origin" side have
whose "origin" side does not. Such a filepair represents "the different number of specified string. Such a filepair represents
string appeared in this changeset". It also checks for the "the string appeared in this changeset". It also checks for the
opposite case that loses the specified string. opposite case that loses the specified string.
When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves When `\--pickaxe-all` is not in effect, diffcore-pickaxe leaves

11
diff.c
View file

@ -3271,12 +3271,17 @@ int diff_opt_parse(struct diff_options *options, const char **av, int ac)
} }
else if ((argcount = short_opt('S', av, &optarg))) { else if ((argcount = short_opt('S', av, &optarg))) {
options->pickaxe = optarg; options->pickaxe = optarg;
options->pickaxe_opts |= DIFF_PICKAXE_KIND_S;
return argcount;
} else if ((argcount = short_opt('G', av, &optarg))) {
options->pickaxe = optarg;
options->pickaxe_opts |= DIFF_PICKAXE_KIND_G;
return argcount; return argcount;
} }
else if (!strcmp(arg, "--pickaxe-all")) else if (!strcmp(arg, "--pickaxe-all"))
options->pickaxe_opts = DIFF_PICKAXE_ALL; options->pickaxe_opts |= DIFF_PICKAXE_ALL;
else if (!strcmp(arg, "--pickaxe-regex")) else if (!strcmp(arg, "--pickaxe-regex"))
options->pickaxe_opts = DIFF_PICKAXE_REGEX; options->pickaxe_opts |= DIFF_PICKAXE_REGEX;
else if ((argcount = short_opt('O', av, &optarg))) { else if ((argcount = short_opt('O', av, &optarg))) {
options->orderfile = optarg; options->orderfile = optarg;
return argcount; return argcount;
@ -4176,7 +4181,7 @@ void diffcore_std(struct diff_options *options)
diffcore_merge_broken(); diffcore_merge_broken();
} }
if (options->pickaxe) if (options->pickaxe)
diffcore_pickaxe(options->pickaxe, options->pickaxe_opts); diffcore_pickaxe(options);
if (options->orderfile) if (options->orderfile)
diffcore_order(options->orderfile); diffcore_order(options->orderfile);
if (!options->found_follow) if (!options->found_follow)

3
diff.h
View file

@ -238,6 +238,9 @@ extern int diff_setup_done(struct diff_options *);
#define DIFF_PICKAXE_ALL 1 #define DIFF_PICKAXE_ALL 1
#define DIFF_PICKAXE_REGEX 2 #define DIFF_PICKAXE_REGEX 2
#define DIFF_PICKAXE_KIND_S 4 /* traditional plumbing counter */
#define DIFF_PICKAXE_KIND_G 8 /* grep in the patch */
extern void diffcore_std(struct diff_options *); extern void diffcore_std(struct diff_options *);
extern void diffcore_fix_diff_index(struct diff_options *); extern void diffcore_fix_diff_index(struct diff_options *);

View file

@ -1,9 +1,148 @@
/* /*
* Copyright (C) 2005 Junio C Hamano * Copyright (C) 2005 Junio C Hamano
* Copyright (C) 2010 Google Inc.
*/ */
#include "cache.h" #include "cache.h"
#include "diff.h" #include "diff.h"
#include "diffcore.h" #include "diffcore.h"
#include "xdiff-interface.h"
struct diffgrep_cb {
regex_t *regexp;
int hit;
};
static void diffgrep_consume(void *priv, char *line, unsigned long len)
{
struct diffgrep_cb *data = priv;
regmatch_t regmatch;
int hold;
if (line[0] != '+' && line[0] != '-')
return;
if (data->hit)
/*
* NEEDSWORK: we should have a way to terminate the
* caller early.
*/
return;
/* Yuck -- line ought to be "const char *"! */
hold = line[len];
line[len] = '\0';
data->hit = !regexec(data->regexp, line + 1, 1, &regmatch, 0);
line[len] = hold;
}
static void fill_one(struct diff_filespec *one,
mmfile_t *mf, struct userdiff_driver **textconv)
{
if (DIFF_FILE_VALID(one)) {
*textconv = get_textconv(one);
mf->size = fill_textconv(*textconv, one, &mf->ptr);
} else {
memset(mf, 0, sizeof(*mf));
}
}
static int diff_grep(struct diff_filepair *p, regex_t *regexp, struct diff_options *o)
{
regmatch_t regmatch;
struct userdiff_driver *textconv_one = NULL;
struct userdiff_driver *textconv_two = NULL;
mmfile_t mf1, mf2;
int hit;
if (diff_unmodified_pair(p))
return 0;
fill_one(p->one, &mf1, &textconv_one);
fill_one(p->two, &mf2, &textconv_two);
if (!mf1.ptr) {
if (!mf2.ptr)
return 0; /* ignore unmerged */
/* created "two" -- does it have what we are looking for? */
hit = !regexec(regexp, p->two->data, 1, &regmatch, 0);
} else if (!mf2.ptr) {
/* removed "one" -- did it have what we are looking for? */
hit = !regexec(regexp, p->one->data, 1, &regmatch, 0);
} else {
/*
* We have both sides; need to run textual diff and see if
* the pattern appears on added/deleted lines.
*/
struct diffgrep_cb ecbdata;
xpparam_t xpp;
xdemitconf_t xecfg;
memset(&xpp, 0, sizeof(xpp));
memset(&xecfg, 0, sizeof(xecfg));
ecbdata.regexp = regexp;
ecbdata.hit = 0;
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
xdi_diff_outf(&mf1, &mf2, diffgrep_consume, &ecbdata,
&xpp, &xecfg);
hit = ecbdata.hit;
}
if (textconv_one)
free(mf1.ptr);
if (textconv_two)
free(mf2.ptr);
return hit;
}
static void diffcore_pickaxe_grep(struct diff_options *o)
{
struct diff_queue_struct *q = &diff_queued_diff;
int i, has_changes, err;
regex_t regex;
struct diff_queue_struct outq;
outq.queue = NULL;
outq.nr = outq.alloc = 0;
err = regcomp(&regex, o->pickaxe, REG_EXTENDED | REG_NEWLINE);
if (err) {
char errbuf[1024];
regerror(err, &regex, errbuf, 1024);
regfree(&regex);
die("invalid log-grep regex: %s", errbuf);
}
if (o->pickaxe_opts & DIFF_PICKAXE_ALL) {
/* Showing the whole changeset if needle exists */
for (i = has_changes = 0; !has_changes && i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (diff_grep(p, &regex, o))
has_changes++;
}
if (has_changes)
return; /* do not munge the queue */
/*
* Otherwise we will clear the whole queue by copying
* the empty outq at the end of this function, but
* first clear the current entries in the queue.
*/
for (i = 0; i < q->nr; i++)
diff_free_filepair(q->queue[i]);
} else {
/* Showing only the filepairs that has the needle */
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (diff_grep(p, &regex, o))
diff_q(&outq, p);
else
diff_free_filepair(p);
}
}
regfree(&regex);
free(q->queue);
*q = outq;
return;
}
static unsigned int contains(struct diff_filespec *one, static unsigned int contains(struct diff_filespec *one,
const char *needle, unsigned long len, const char *needle, unsigned long len,
@ -48,8 +187,10 @@ static unsigned int contains(struct diff_filespec *one,
return cnt; return cnt;
} }
void diffcore_pickaxe(const char *needle, int opts) static void diffcore_pickaxe_count(struct diff_options *o)
{ {
const char *needle = o->pickaxe;
int opts = o->pickaxe_opts;
struct diff_queue_struct *q = &diff_queued_diff; struct diff_queue_struct *q = &diff_queued_diff;
unsigned long len = strlen(needle); unsigned long len = strlen(needle);
int i, has_changes; int i, has_changes;
@ -136,3 +277,12 @@ void diffcore_pickaxe(const char *needle, int opts)
*q = outq; *q = outq;
return; return;
} }
void diffcore_pickaxe(struct diff_options *o)
{
/* Might want to warn when both S and G are on; I don't care... */
if (o->pickaxe_opts & DIFF_PICKAXE_KIND_G)
return diffcore_pickaxe_grep(o);
else
return diffcore_pickaxe_count(o);
}

View file

@ -107,7 +107,7 @@ extern void diff_q(struct diff_queue_struct *, struct diff_filepair *);
extern void diffcore_break(int); extern void diffcore_break(int);
extern void diffcore_rename(struct diff_options *); extern void diffcore_rename(struct diff_options *);
extern void diffcore_merge_broken(void); extern void diffcore_merge_broken(void);
extern void diffcore_pickaxe(const char *needle, int opts); extern void diffcore_pickaxe(struct diff_options *);
extern void diffcore_order(const char *orderfile); extern void diffcore_order(const char *orderfile);
#define DIFF_DEBUG 0 #define DIFF_DEBUG 0

View file

@ -210,6 +210,9 @@ log -m -p master
log -SF master log -SF master
log -S F master log -S F master
log -SF -p master log -SF -p master
log -GF master
log -GF -p master
log -GF -p --pickaxe-all master
log --decorate --all log --decorate --all
log --decorate=full --all log --decorate=full --all

View file

@ -0,0 +1,27 @@
$ git log -GF -p --pickaxe-all master
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
diff --git a/dir/sub b/dir/sub
index 8422d40..cead32e 100644
--- a/dir/sub
+++ b/dir/sub
@@ -2,3 +2,5 @@ A
B
C
D
+E
+F
diff --git a/file1 b/file1
new file mode 100644
index 0000000..b1e6722
--- /dev/null
+++ b/file1
@@ -0,0 +1,3 @@
+A
+B
+C
$

View file

@ -0,0 +1,18 @@
$ git log -GF -p master
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
diff --git a/dir/sub b/dir/sub
index 8422d40..cead32e 100644
--- a/dir/sub
+++ b/dir/sub
@@ -2,3 +2,5 @@ A
B
C
D
+E
+F
$

View file

@ -0,0 +1,7 @@
$ git log -GF master
commit 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:02:00 2006 +0000
Third
$