diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 00ccf68744103d..db0979ac49855c 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -71,6 +71,14 @@ endif::git-rev-list[] Limit the commits output to ones that match all given `--grep`, instead of ones that match at least one. +--match-header-or-grep:: + Limit the commits output to ones that match either header patterns + (`--author`, `--committer`, or `--grep-reflog`) or `--grep`, instead + of ones that match both the header and grep patterns ++ +For example, `--author=me --grep=Co-authored-by: me` limits to commits either +authored or co-authored by me. + --invert-grep:: Limit the commits output to ones with a log message that do not match the pattern specified with `--grep=`. diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 75193ded4bdeda..30fc6ed08bd922 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -2170,7 +2170,7 @@ __git_log_gitk_options=" # Options that go well for log and shortlog (not gitk) __git_log_shortlog_options=" --author= --committer= --grep= - --all-match --invert-grep + --all-match --invert-grep --match-header-or-grep " # Options accepted by log and show __git_log_show_options=" diff --git a/grep.c b/grep.c index ac34bfeafb3c91..72cf599660aaa6 100644 --- a/grep.c +++ b/grep.c @@ -802,7 +802,7 @@ void compile_grep_patterns(struct grep_opt *opt) if (!opt->pattern_expression) opt->pattern_expression = header_expr; - else if (opt->all_match) + else if (opt->all_match || opt->match_header_or_grep) opt->pattern_expression = grep_splice_or(header_expr, opt->pattern_expression); else @@ -1829,7 +1829,7 @@ int grep_source(struct grep_opt *opt, struct grep_source *gs) opt->body_hit = 0; grep_source_1(opt, gs, 1); - if (opt->all_match && !chk_hit_marker(opt->pattern_expression)) + if (!opt->match_header_or_grep && opt->all_match && !chk_hit_marker(opt->pattern_expression)) return 0; if (opt->no_body_match && opt->body_hit) return 0; diff --git a/grep.h b/grep.h index 926c0875c42f63..861584dba988d3 100644 --- a/grep.h +++ b/grep.h @@ -147,6 +147,7 @@ struct grep_opt { int count; int word_regexp; int all_match; + int match_header_or_grep; int no_body_match; int body_hit; #define GREP_BINARY_DEFAULT 0 diff --git a/revision.c b/revision.c index 7e45f765d9fe16..786c229f56d108 100644 --- a/revision.c +++ b/revision.c @@ -2646,6 +2646,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_PCRE; } else if (!strcmp(arg, "--all-match")) { revs->grep_filter.all_match = 1; + } else if (!strcmp(arg, "--match-header-or-grep")) { + revs->grep_filter.match_header_or_grep = 1; } else if (!strcmp(arg, "--invert-grep")) { revs->grep_filter.no_body_match = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 875dcfd98f3a0e..c78ce150f4de5a 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -961,6 +961,14 @@ test_expect_success 'log --grep --author uses intersection' ' test_cmp expect actual ' +test_expect_success 'log --grep --author --match-header-or-grep uses union' ' + # grep matches only third and fourth + # author matches only initial and third + git log --author="A U Thor" --grep=r --match-header-or-grep --format=%s >actual && + test_write_lines fourth third initial >expect && + test_cmp expect actual +' + test_expect_success 'log --grep --grep --author takes union of greps and intersects with author' ' # grep matches initial and second but not third # author matches only initial and third @@ -971,7 +979,23 @@ test_expect_success 'log --grep --grep --author takes union of greps and interse test_cmp expect actual ' -test_expect_success 'log ---all-match -grep --author --author still takes union of authors and intersects with grep' ' +test_expect_success 'log --author --grep --grep --match-header-or-grep takes union of greps and author' ' + # grep matches initial and second but not third + # author matches only initial and third + git log --author="A U Thor" --grep=second --grep=initial --match-header-or-grep --format=%s >actual && + test_write_lines third second initial >expect && + test_cmp expect actual +' + +test_expect_success 'log --author --grep --grep --all-match --match-header-or-grep still takes union of greps and author' ' + # grep matches initial and second but not third + # author matches only initial and third + git log --author="A U Thor" --grep=second --grep=initial --all-match --match-header-or-grep --format=%s >actual && + test_write_lines third second initial >expect && + test_cmp expect actual +' + +test_expect_success 'log --all-match --grep --author --author still takes union of authors and intersects with grep' ' # grep matches only initial and third # author matches all but second git log --all-match --author="Thor" --author="Night" --grep=i --format=%s >actual &&