Skip to content

Commit 13e4fc7

Browse files
committed
log --grep/--author: honor --all-match honored for multiple --grep patterns
When we have both header expression (which has to be an OR node by construction) and a pattern expression (which could be anything), we create a new top-level OR node to bind them together, and the resulting expression structure looks like this: OR / \ / \ pattern OR / \ / \ ..... committer OR / \ author TRUE The three elements on the top-level backbone that are inspected by the "all-match" logic are "pattern", "committer" and "author". When there are more than one elements in the "pattern", the top-level node of the "pattern" part of the subtree is an OR, and that node is inspected by "all-match". The result ends up ignoring the "--all-match" given from the command line. A match on either side of the pattern is considered a match, hence: git log --grep=A --grep=B --author=C --all-match shows the same "authored by C and has either A or B" that is correct only when run without "--all-match". Fix this by turning the resulting expression around when "--all-match" is in effect, like this: OR / \ / \ / OR committer / \ author \ pattern The set of nodes on the top-level backbone in the resulting expression becomes "committer", "author", and the nodes that are on the top-level backbone of the "pattern" subexpression. This makes the "all-match" logic inspect the same nodes in "pattern" as the case without the author and/or the committer restriction, and makes the earlier "log" example to show "authored by C and has A and has B", which is what the command line expects. Signed-off-by: Junio C Hamano <[email protected]>
1 parent 208f5aa commit 13e4fc7

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

grep.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,22 @@ static struct grep_expr *prep_header_patterns(struct grep_opt *opt)
476476
return header_expr;
477477
}
478478

479+
static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr *y)
480+
{
481+
struct grep_expr *z = x;
482+
483+
while (x) {
484+
assert(x->node == GREP_NODE_OR);
485+
if (x->u.binary.right &&
486+
x->u.binary.right->node == GREP_NODE_TRUE) {
487+
x->u.binary.right = y;
488+
break;
489+
}
490+
x = x->u.binary.right;
491+
}
492+
return z;
493+
}
494+
479495
static void compile_grep_patterns_real(struct grep_opt *opt)
480496
{
481497
struct grep_pat *p;
@@ -510,6 +526,9 @@ static void compile_grep_patterns_real(struct grep_opt *opt)
510526

511527
if (!opt->pattern_expression)
512528
opt->pattern_expression = header_expr;
529+
else if (opt->all_match)
530+
opt->pattern_expression = grep_splice_or(header_expr,
531+
opt->pattern_expression);
513532
else
514533
opt->pattern_expression = grep_or_expr(opt->pattern_expression,
515534
header_expr);

0 commit comments

Comments
 (0)