From: Junio C Hamano <>

Earlier, when we have both header expression (which has to be an OR
node by construction) and a pattern expression (which could be
anything), we created a top-level OR node that looks like this to
bind them together:

        /          \
       /            \
   pattern            OR
     / \           /     \
    .....    committer    OR
                         /   \
                     author   TRUE

In other words, the three elements on the top-level backbone that
were 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 it is that OR, so that node is
inspected by "all-match", hence the result ends up ignoring the
"--all-match" given from the command line.  A match on either side
of the pattern was considered a match, hence

        git log --grep=A --grep=B --author=C --all-match

showed the same "authored by C and has either A or B" with or
without --all-match.

This patch turns the grep expression into this form:

          /       \
         /          \
        /              OR
    committer        /    \
                 author    \

when "--all-match" was given from the command line.  This way, the
set of nodes on the top-level backbone in the resulting expression
consists of "committer", "author", and whatever nodes were on the
top-level backbone of the "pattern" expression.  The "all-match"
logic inspects the same nodes in "pattern" as the case without the
author and/or the committer restriction.

Signed-off-by: Junio C Hamano <>
Signed-off-by: Michael J Gruber <>
 grep.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/grep.c b/grep.c
index be15c47..925aa92 100644
--- a/grep.c
+++ b/grep.c
@@ -476,6 +476,22 @@ static struct grep_expr *prep_header_patterns(struct 
grep_opt *opt)
        return header_expr;
+static struct grep_expr *grep_splice_or(struct grep_expr *x, struct grep_expr 
+       struct grep_expr *z = x;
+       while (x) {
+               assert(x->node == GREP_NODE_OR);
+               if (x->u.binary.right &&
+                   x->u.binary.right->node == GREP_NODE_TRUE) {
+                       x->u.binary.right = y;
+                       break;
+               }
+               x = x->u.binary.right;
+       }
+       return z;
 static void compile_grep_patterns_real(struct grep_opt *opt)
        struct grep_pat *p;
@@ -510,6 +526,9 @@ static void compile_grep_patterns_real(struct grep_opt *opt)
        if (!opt->pattern_expression)
                opt->pattern_expression = header_expr;
+       else if (opt->all_match)
+               opt->pattern_expression = grep_splice_or(header_expr,
                opt->pattern_expression = grep_or_expr(opt->pattern_expression,

To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to
More majordomo info at

Reply via email to