From: Sven Verdoolaege <hidden> Date: 2016-06-15 22:43:20
We do this by maintaining two lists of patterns, one for
those that should match and one for those that should not match.
Signed-off-by: Sven Verdoolaege <redacted>
---
Documentation/git-rev-list.txt | 7 ++++-
revision.c | 57 ++++++++++++++++++++++++++++-----------
revision.h | 1 +
3 files changed, 48 insertions(+), 17 deletions(-)
@@ -214,11 +214,15 @@ limiting may be applied. Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression).+ If this option is preceded by an odd number of --not options,+ then only commits that do not match will be shown. --grep='pattern':: Limit the commits output to ones with log message that matches the specified pattern (regular expression).+ If this option is preceded by an odd number of --not options,+ then only commits that do not match will be shown. --regexp-ignore-case::
@@ -248,7 +252,8 @@ limiting may be applied. --not:: Reverses the meaning of the '{caret}' prefix (or lack thereof)- for all following revision specifiers, up to the next '--not'.+ for all following revision specifiers as well as the result+ of matching a pattern, up to the next '--not'. --all::
@@ -1329,11 +1351,14 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)staticintcommit_match(structcommit*commit,structrev_info*opt){-if(!opt->grep_filter)-return1;-returngrep_buffer(opt->grep_filter,+return(!opt->grep_filter||+grep_buffer(opt->grep_filter,+NULL,/* we say nothing, not even filename */+commit->buffer,strlen(commit->buffer)))&&+(!opt->grep_neg_filter||+!grep_buffer(opt->grep_neg_filter,NULL,/* we say nothing, not even filename */-commit->buffer,strlen(commit->buffer));+commit->buffer,strlen(commit->buffer)));}staticstructcommit*get_revision_1(structrev_info*revs)
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:43:20
Hi,
On Sat, 7 Jul 2007, Sven Verdoolaege wrote:
We do this by maintaining two lists of patterns, one for
those that should match and one for those that should not match.
I suspect that with this patch,
git rev-list --not --grep bugfix HEAD
does not work as expected. Why? Because the --not is heeded when
interpreting "HEAD". And that is confusing, because you use --not for two
completely unrelated things.
Why not make "git rev-list --grep '!bugfix' HEAD" work?
Yes, you would have to have a special exception that the prefix "!!"
actually matches an exclamation mark, but I'd be willing to live with
that.
Ciao,
Dscho
From: Sven Verdoolaege <hidden> Date: 2016-06-15 22:43:20
On Sat, Jul 07, 2007 at 05:27:23PM +0100, Johannes Schindelin wrote:
I suspect that with this patch,
git rev-list --not --grep bugfix HEAD
does not work as expected. Why?
Well... I guess that depends on what you expect...
Why not make "git rev-list --grep '!bugfix' HEAD" work?
Yes, you would have to have a special exception that the prefix "!!"
actually matches an exclamation mark, but I'd be willing to live with
that.
Hmm... what if you want to (not) match anything starting with
one or more '!' ?
How about I add a '--invert-match' option that would
apply to all following match options?
Or we could escape the '!' with backslash.
skimo
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:43:20
Hi,
On Sat, 7 Jul 2007, Sven Verdoolaege wrote:
On Sat, Jul 07, 2007 at 05:27:23PM +0100, Johannes Schindelin wrote:
quoted
I suspect that with this patch,
git rev-list --not --grep bugfix HEAD
does not work as expected. Why?
Well... I guess that depends on what you expect...
Well, at least you hopefully that it is confusing. To use --not for grep
patterns _as well_ as for revision arguments.
quoted
Why not make "git rev-list --grep '!bugfix' HEAD" work?
Yes, you would have to have a special exception that the prefix "!!"
actually matches an exclamation mark, but I'd be willing to live with
that.
Hmm... what if you want to (not) match anything starting with
one or more '!' ?
Yeah, that would not work.
How about I add a '--invert-match' option that would
apply to all following match options?
Or we could escape the '!' with backslash.
If we want to match it at the beginning. Yes, that sounds more reasonable
to me.
Ciao,
Dscho
From: Sven Verdoolaege <hidden> Date: 2016-06-15 22:43:20
We do this by maintaining two lists of patterns, one for
those that should match and one for those that should not match.
Signed-off-by: Sven Verdoolaege <redacted>
---
Documentation/git-rev-list.txt | 8 +++++
revision.c | 59 +++++++++++++++++++++++++++++++--------
revision.h | 1 +
3 files changed, 56 insertions(+), 12 deletions(-)
@@ -214,11 +214,19 @@ limiting may be applied. Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --grep='pattern':: Limit the commits output to ones with log message that matches the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --regexp-ignore-case::
@@ -1329,11 +1361,14 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)staticintcommit_match(structcommit*commit,structrev_info*opt){-if(!opt->grep_filter)-return1;-returngrep_buffer(opt->grep_filter,+return(!opt->grep_filter||+grep_buffer(opt->grep_filter,+NULL,/* we say nothing, not even filename */+commit->buffer,strlen(commit->buffer)))&&+(!opt->grep_neg_filter||+!grep_buffer(opt->grep_neg_filter,NULL,/* we say nothing, not even filename */-commit->buffer,strlen(commit->buffer));+commit->buffer,strlen(commit->buffer)));}staticstructcommit*get_revision_1(structrev_info*revs)
Why not keep it "add_grep", and do a
struct grep_opt **filter = negated ?
&revs->grep_neg_filter : &revs->grep_filter;
Hm? You avoid an extra function that way.
The parsing for "!" is again duplicated in add_message_grep(). Why not put
it into add_grep(), and do
negated = *pattern == '!';
sprintf(pat, "%s^%s %s%s", negated ? "!" : "", field, prefix,
pattern + negated);
instead? No need to change the signature of add_grep(), and all callers
get the '!' feature for free.
@@ -1329,11 +1361,14 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit) static int commit_match(struct commit *commit, struct rev_info *opt) {- if (!opt->grep_filter)- return 1;- return grep_buffer(opt->grep_filter,+ return (!opt->grep_filter ||+ grep_buffer(opt->grep_filter,+ NULL, /* we say nothing, not even filename */+ commit->buffer, strlen(commit->buffer))) &&+ (!opt->grep_neg_filter ||+ !grep_buffer(opt->grep_neg_filter, NULL, /* we say nothing, not even filename */- commit->buffer, strlen(commit->buffer));+ commit->buffer, strlen(commit->buffer))); }
Urgh! That's not nice on my eyes.
Also, I suspect that the semantics are not yet clear, what should happen
if all_match is unset.
BTW I suspect that a better way than having two filter lists is
demonstrated in builtin-grep.c.
Ciao,
Dscho
From: Sven Verdoolaege <hidden> Date: 2016-06-15 22:43:20
On Sat, Jul 07, 2007 at 08:35:35PM +0100, Johannes Schindelin wrote:
Why not keep it "add_grep", and do a
struct grep_opt **filter = negated ?
&revs->grep_neg_filter : &revs->grep_filter;
Hm? You avoid an extra function that way.
[..]
The parsing for "!" is again duplicated in add_message_grep(). Why not put
it into add_grep(), and do
negated = *pattern == '!';
sprintf(pat, "%s^%s %s%s", negated ? "!" : "", field, prefix,
pattern + negated);
instead? No need to change the signature of add_grep(), and all callers
get the '!' feature for free.
I can do these things, but they don't exactly improve readability, IMHO.
I may still need them for doing something with all_match...
quoted
@@ -1329,11 +1361,14 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit) static int commit_match(struct commit *commit, struct rev_info *opt) {- if (!opt->grep_filter)- return 1;- return grep_buffer(opt->grep_filter,+ return (!opt->grep_filter ||+ grep_buffer(opt->grep_filter,+ NULL, /* we say nothing, not even filename */+ commit->buffer, strlen(commit->buffer))) &&+ (!opt->grep_neg_filter ||+ !grep_buffer(opt->grep_neg_filter, NULL, /* we say nothing, not even filename */- commit->buffer, strlen(commit->buffer));+ commit->buffer, strlen(commit->buffer))); }
Urgh! That's not nice on my eyes.
You prefer
if (opt->grep_filter && !grep_buffer(opt->grep_filter,
NULL, /* we say nothing, not even filename */
commit->buffer, strlen(commit->buffer)))
return 0;
if (opt->grep_neg_filter && grep_buffer(opt->grep_neg_filter,
NULL, /* we say nothing, not even filename */
commit->buffer, strlen(commit->buffer)));
return 0;
return 1;
?
Also, I suspect that the semantics are not yet clear, what should happen
if all_match is unset.
So what are the semantics of all_match without negated matches?
It doesn't seem to be documented in git-rev-list.txt.
BTW I suspect that a better way than having two filter lists is
demonstrated in builtin-grep.c.
Could you be a bit more specific?
If you're talking about the GREP_NOT thing, then AFAICS that is line based
and I want these things to be commit based. That is I want to select
commits with either a or no lines that match a given pattern and not
commits that have a line that matches some patterns and not some others.
skimo
From: Sven Verdoolaege <hidden> Date: 2016-06-15 22:43:20
We do this by maintaining two lists of patterns, one for
those that should match and one for those that should not match.
A negative pattern is specified by putting a '!' in front.
For example, to show the commits of Jakub Narebski that
are not about gitweb, you'd do a
git log --author='Narebski' --grep='!gitweb' --all-match
As an added bonus, this patch also documents --all-match.
Signed-off-by: Sven Verdoolaege <redacted>
---
Documentation/git-rev-list.txt | 17 ++++++++++
revision.c | 64 +++++++++++++++++++++++++++++++++------
revision.h | 1 +
3 files changed, 72 insertions(+), 10 deletions(-)
@@ -214,11 +214,19 @@ limiting may be applied. Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --grep='pattern':: Limit the commits output to ones with log message that matches the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --regexp-ignore-case::
@@ -229,6 +237,15 @@ limiting may be applied. Consider the limiting patterns to be extended regular expressions instead of the default basic regular expressions.+--all-match::++ Without this option, a commit is shown if any of the+ (positive or negative) patterns matches, i.e., there+ is at least one positive match or not all of the negative+ patterns match. With this options, a commit is only+ shown if all of the patterns match, i.e., all positive+ patterns match and no negative pattern matches.+ --remove-empty:: Stop when a given path disappears from the tree.
@@ -1327,11 +1351,31 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)return0;}+/*+*Ifall_matchisset,thenacommitmatchesifallthepositive+*patternsmatchandnotoneofthenegativepatternsmatches.+*Ifall_matchisnotset,thenacommitmatchesifatleastone+*ofthepositivepatternsmatchesornotallofthenegative+*patternsmatch.+*/staticintcommit_match(structcommit*commit,structrev_info*opt){-if(!opt->grep_filter)+intpos_match,all_match;++pos_match=!opt->grep_filter||+grep_buffer(opt->grep_filter,+NULL,/* we say nothing, not even filename */+commit->buffer,strlen(commit->buffer));+if(!opt->grep_neg_filter)+returnpos_match;++all_match=!opt->grep_neg_filter->all_match;+if(!all_match&&opt->grep_filter&&pos_match)return1;-returngrep_buffer(opt->grep_filter,+if(all_match&&!pos_match)+return0;++return!grep_buffer(opt->grep_neg_filter,NULL,/* we say nothing, not even filename */commit->buffer,strlen(commit->buffer));}
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:43:20
Hi,
just to give you an impression of what I had in mind, here is a WIP. It
is not completely thought through, for example I did not make up my mind
how to handle something like "--not --not-at-all <pattern>". Oh, and the
code for non-status_only is not there. And builtin-grep does not see any
of this, yet. But you'll get the idea:
---
grep.c | 19 +++++++++++++++----
grep.h | 3 +++
revision.c | 13 ++++++++++++-
3 files changed, 30 insertions(+), 5 deletions(-)
@@ -66,20 +66,24 @@ static struct grep_expr *compile_pattern_atom(struct grep_pat **list)staticstructgrep_expr*compile_pattern_not(structgrep_pat**list){+constchar*what;structgrep_pat*p;structgrep_expr*x;p=*list;switch(p->token){caseGREP_NOT:+caseGREP_NOT_AT_ALL:+what=p->token==GREP_NOT?"--not":"--not-at-all";if(!p->next)-die("--not not followed by pattern expression");+die("%s not followed by pattern expression",what);*list=p->next;x=xcalloc(1,sizeof(structgrep_expr));-x->node=GREP_NODE_NOT;+x->node=p->token==GREP_NOT?+GREP_NODE_NOT:GREP_NODE_NOT_AT_ALL;x->u.unary=compile_pattern_not(list);if(!x->u.unary)-die("--not followed by non pattern expression");+die("%s followed by non pattern expression",what);returnx;default:returncompile_pattern_atom(list);
@@ -500,7 +511,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,return0;if(opt->status_only)-return0;+return!opt->not_at_all;if(opt->unmatch_name_only){/* We did not see any hit, so we want to show this */printf("%s\n",name);
@@ -68,6 +70,7 @@ struct grep_opt {unsignedextended:1;unsignedrelative:1;unsignedpathname:1;+unsignednot_at_all:1;/* is set if the pattern was seen */intregflags;unsignedpre_context;unsignedpost_context;
@@ -500,7 +511,7 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name, return 0; if (opt->status_only)- return 0;+ return !opt->not_at_all; if (opt->unmatch_name_only) { /* We did not see any hit, so we want to show this */ printf("%s\n", name);
I don't understand this part.
Aren't you changing the return value from 0 to 1 here if there is no NOT_AT_ALL node?
quoted hunk
@@ -68,6 +70,7 @@ struct grep_opt { unsigned extended:1; unsigned relative:1; unsigned pathname:1;+ unsigned not_at_all:1; /* is set if the pattern was seen */ int regflags; unsigned pre_context; unsigned post_context;
The name for this field is also a bit confusing.
Wouldn't "matched_some_line" or some such by more appropriate?
skimo
From: Jeff King <hidden> Date: 2016-06-15 22:43:20
On Sun, Jul 08, 2007 at 12:57:20PM +0200, Sven Verdoolaege wrote:
We do this by maintaining two lists of patterns, one for
those that should match and one for those that should not match.
A negative pattern is specified by putting a '!' in front.
For example, to show the commits of Jakub Narebski that
are not about gitweb, you'd do a
git log --author='Narebski' --grep='!gitweb' --all-match
I wondered if the usage might be more natural if we could grep in
separate processes, and then build filtering pipelines (like we would
with regular grep). For example, something like:
git-rev-list HEAD |
git-revgrep --author=Narebski |
git-revgrep -v gitweb |
git-log -
However, my concern was that things might get a lot slower. And they do:
$ time git-rev-list --grep=Jeff.King HEAD >/dev/null
real 0m0.553s
user 0m0.532s
sys 0m0.020s
$ time git-rev-list HEAD | git-revgrep Jeff.King >/dev/null
real 0m0.662s
user 0m1.072s
sys 0m0.036s
(note the user time -- it's a dual-CPU box, so the wall clock time is
deceptive).
So it really does double your time (or triple, if you have a second
revgrep, and so forth (although as you filter out commits the cost of
each successive revgrep goes down)). So it's probably not worth
pursuing this approach, but I thought I would throw it out there to
document my dead-end.
Quick and dirty git-revgrep code is below.
-Peff
---
@@ -214,11 +214,19 @@ limiting may be applied. Limit the commits output to ones with author/committer header lines that match the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --grep='pattern':: Limit the commits output to ones with log message that matches the specified pattern (regular expression).+ A pattern starting with a '!' will show only commits that do+ not match the remainder of the pattern.+ To match lines starting with '!', escape the initial '!'+ with a backslash. --regexp-ignore-case::
@@ -229,6 +237,15 @@ limiting may be applied. Consider the limiting patterns to be extended regular expressions instead of the default basic regular expressions.+--all-match::++ Without this option, a commit is shown if any of the+ (positive or negative) patterns matches, i.e., there+ is at least one positive match or not all of the negative+ patterns match. With this options, a commit is only+ shown if all of the patterns match, i.e., all positive+ patterns match and no negative pattern matches.+ --remove-empty:: Stop when a given path disappears from the tree.
@@ -1327,11 +1351,31 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)return0;}+/*+*Ifall_matchisset,thenacommitmatchesifallthepositive+*patternsmatchandnotoneofthenegativepatternsmatches.+*Ifall_matchisnotset,thenacommitmatchesifatleastone+*ofthepositivepatternsmatchesornotallofthenegative+*patternsmatch.+*/staticintcommit_match(structcommit*commit,structrev_info*opt){-if(!opt->grep_filter)+intpos_match,all_match;++pos_match=!opt->grep_filter||+grep_buffer(opt->grep_filter,+NULL,/* we say nothing, not even filename */+commit->buffer,strlen(commit->buffer));+if(!opt->grep_neg_filter)+returnpos_match;++all_match=!opt->grep_neg_filter->all_match;+if(!all_match&&opt->grep_filter&&pos_match)return1;-returngrep_buffer(opt->grep_filter,+if(all_match&&!pos_match)+return0;++return!grep_buffer(opt->grep_neg_filter,NULL,/* we say nothing, not even filename */commit->buffer,strlen(commit->buffer));}
@@ -84,6 +84,7 @@ struct rev_info {/* Filter by commit log message */structgrep_opt*grep_filter;+structgrep_opt*grep_neg_filter;/* special limits */intskip_count;
--
1.5.3.rc0.65.ge75d-dirty
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html