Skip to content

Commit 794c000

Browse files
rscharfegitster
authored andcommitted
log: let --invert-grep only invert --grep
The option --invert-grep is documented to filter out commits whose messages match the --grep filters. However, it also affects the header matches (--author, --committer), which is not intended. Move the handling of that option to grep.c, as only the code there can distinguish between matches in the header from those in the message body. If --invert-grep is given then enable extended expressions (not the regex type, we just need git grep's --not to work), negate the body patterns and check if any of them match by piggy-backing on the collect_hits mechanism of grep_source_1(). Collecting the matches in struct grep_opt is a bit iffy, but with "last_shown" we have a precedent for writing state information to that struct. Reported-by: Dotan Cohen <[email protected]> Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent e9d7761 commit 794c000

File tree

5 files changed

+42
-7
lines changed

5 files changed

+42
-7
lines changed

grep.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,14 @@ static struct grep_expr *compile_pattern_expr(struct grep_pat **list)
699699
return compile_pattern_or(list);
700700
}
701701

702+
static struct grep_expr *grep_not_expr(struct grep_expr *expr)
703+
{
704+
struct grep_expr *z = xcalloc(1, sizeof(*z));
705+
z->node = GREP_NODE_NOT;
706+
z->u.unary = expr;
707+
return z;
708+
}
709+
702710
static struct grep_expr *grep_true_expr(void)
703711
{
704712
struct grep_expr *z = xcalloc(1, sizeof(*z));
@@ -797,7 +805,7 @@ void compile_grep_patterns(struct grep_opt *opt)
797805
}
798806
}
799807

800-
if (opt->all_match || header_expr)
808+
if (opt->all_match || opt->no_body_match || header_expr)
801809
opt->extended = 1;
802810
else if (!opt->extended)
803811
return;
@@ -808,6 +816,9 @@ void compile_grep_patterns(struct grep_opt *opt)
808816
if (p)
809817
die("incomplete pattern expression: %s", p->pattern);
810818

819+
if (opt->no_body_match && opt->pattern_expression)
820+
opt->pattern_expression = grep_not_expr(opt->pattern_expression);
821+
811822
if (!header_expr)
812823
return;
813824

@@ -1057,6 +1068,8 @@ static int match_expr_eval(struct grep_opt *opt, struct grep_expr *x,
10571068
if (h && (*col < 0 || tmp.rm_so < *col))
10581069
*col = tmp.rm_so;
10591070
}
1071+
if (x->u.atom->token == GREP_PATTERN_BODY)
1072+
opt->body_hit |= h;
10601073
break;
10611074
case GREP_NODE_NOT:
10621075
/*
@@ -1825,16 +1838,19 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs)
18251838
* we do not have to do the two-pass grep when we do not check
18261839
* buffer-wide "all-match".
18271840
*/
1828-
if (!opt->all_match)
1841+
if (!opt->all_match && !opt->no_body_match)
18291842
return grep_source_1(opt, gs, 0);
18301843

18311844
/* Otherwise the toplevel "or" terms hit a bit differently.
18321845
* We first clear hit markers from them.
18331846
*/
18341847
clr_hit_marker(opt->pattern_expression);
1848+
opt->body_hit = 0;
18351849
grep_source_1(opt, gs, 1);
18361850

1837-
if (!chk_hit_marker(opt->pattern_expression))
1851+
if (opt->all_match && !chk_hit_marker(opt->pattern_expression))
1852+
return 0;
1853+
if (opt->no_body_match && opt->body_hit)
18381854
return 0;
18391855

18401856
return grep_source_1(opt, gs, 0);

grep.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ struct grep_opt {
148148
int word_regexp;
149149
int fixed;
150150
int all_match;
151+
int no_body_match;
152+
int body_hit;
151153
#define GREP_BINARY_DEFAULT 0
152154
#define GREP_BINARY_NOMATCH 1
153155
#define GREP_BINARY_TEXT 2

revision.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2493,7 +2493,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
24932493
} else if (!strcmp(arg, "--all-match")) {
24942494
revs->grep_filter.all_match = 1;
24952495
} else if (!strcmp(arg, "--invert-grep")) {
2496-
revs->invert_grep = 1;
2496+
revs->grep_filter.no_body_match = 1;
24972497
} else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
24982498
if (strcmp(optarg, "none"))
24992499
git_log_output_encoding = xstrdup(optarg);
@@ -3778,7 +3778,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
37783778
(char *)message, strlen(message));
37793779
strbuf_release(&buf);
37803780
unuse_commit_buffer(commit, message);
3781-
return opt->invert_grep ? !retval : retval;
3781+
return retval;
37823782
}
37833783

37843784
static inline int want_ancestry(const struct rev_info *revs)

revision.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,6 @@ struct rev_info {
246246

247247
/* Filter by commit log message */
248248
struct grep_opt grep_filter;
249-
/* Negate the match of grep_filter */
250-
int invert_grep;
251249

252250
/* Display history graph */
253251
struct git_graph *graph;

t/t4202-log.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2010,4 +2010,23 @@ test_expect_success 'log --end-of-options' '
20102010
test_cmp expect actual
20112011
'
20122012

2013+
test_expect_success 'set up commits with different authors' '
2014+
git checkout --orphan authors &&
2015+
test_commit --author "Jim <[email protected]>" jim_1 &&
2016+
test_commit --author "Val <[email protected]>" val_1 &&
2017+
test_commit --author "Val <[email protected]>" val_2 &&
2018+
test_commit --author "Jim <[email protected]>" jim_2 &&
2019+
test_commit --author "Val <[email protected]>" val_3 &&
2020+
test_commit --author "Jim <[email protected]>" jim_3
2021+
'
2022+
2023+
test_expect_success 'log --invert-grep --grep --author' '
2024+
cat >expect <<-\EOF &&
2025+
val_3
2026+
val_1
2027+
EOF
2028+
git log --format=%s --author=Val --grep 2 --invert-grep >actual &&
2029+
test_cmp expect actual
2030+
'
2031+
20132032
test_done

0 commit comments

Comments
 (0)