From: "Max Coplan via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: "Phillip Wood" <phillip.wood123@gmail.com>,
strager <strager.nds@gmail.com>, me <mchcopl@gmail.com>,
"Max Coplan" <mchcopl@gmail.com>,
"Max 👨🏽💻 Coplan" <mchcopl@gmail.com>
Subject: [PATCH v2] log: add option to search for header or body
Date: Sun, 07 Apr 2024 03:24:07 +0000 [thread overview]
Message-ID: <pull.1710.v2.git.1712460247516.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1710.git.1712353687464.gitgitgadget@gmail.com>
From: =?UTF-8?q?Max=20=F0=9F=91=A8=F0=9F=8F=BD=E2=80=8D=F0=9F=92=BB=20Copl?=
=?UTF-8?q?an?= <mchcopl@gmail.com>
Summary:
This change adds a new option to `git log` that allows users to search
for commits that match either the author or the commit message. This is
useful for finding commits that were either authored or co-authored by a
specific person.
Currently, the best way to find a commit either authored or co-authored
by a specific person is to use
```sh
$ echo \
$(git log --author=Torvalds --pretty="%cd,%H\n" --date=iso-strict) \
$(git log --grep="Co-authored-by: .*Torvalds" --pretty="%cd,%H\n" --date=iso-strict) \
| sort -n --reverse \
| awk -F, '{print $2}' \
| tr '\n' '\t' \
| xargs git show --stat --stdin
```
This is a bit of a pain, so this change adds a new option to `git log`.
Now finding either authors or co-authors is as simple as
```sh
$ git log --author=Torvalds --grep=Torvalds --match-header-or-grep
```
Test plan:
1. create commit authored by A and co-authored-by B
2. create commit authored by B
3. run
```sh
$ git log --author=B --grep="Co-authored-by: B" --match-header-or-grep
```
4. expect to see both commits
Signed-off-by: Max 👨🏽💻 Coplan <mchcopl@gmail.com>
---
log: add option to search for header or body
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1710%2Fvegerot%2Fheader-or-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1710/vegerot/header-or-v2
Pull-Request: https://github.com/gitgitgadget/git/pull/1710
Range-diff vs v1:
1: dc6b5664159 ! 1: c7f14e59b4f feat(log): add option to search for header or body to `git log`
@@ Metadata
Author: Max 👨🏽💻 Coplan <mchcopl@gmail.com>
## Commit message ##
- feat(log): add option to search for header or body to `git log`
-
- Note to reviewer: I hate the name `--header-or`! Please help me come up
- with a better name.
+ log: add option to search for header or body
Summary:
This change adds a new option to `git log` that allows users to search
@@ Commit message
by a specific person is to use
```sh
- echo \
+ $ echo \
$(git log --author=Torvalds --pretty="%cd,%H\n" --date=iso-strict) \
$(git log --grep="Co-authored-by: .*Torvalds" --pretty="%cd,%H\n" --date=iso-strict) \
| sort -n --reverse \
@@ Commit message
Now finding either authors or co-authors is as simple as
```sh
- git log --author=Torvalds --grep=Torvalds --header-or
+ $ git log --author=Torvalds --grep=Torvalds --match-header-or-grep
```
Test plan:
1. create commit authored by A and co-authored-by B
2. create commit authored by B
- 3. run `git log --author=B --grep="Co-authored-by: B" --header-or`
+ 3. run
+ ```sh
+ $ git log --author=B --grep="Co-authored-by: B" --match-header-or-grep
+ ```
4. expect to see both commits
Signed-off-by: Max 👨🏽💻 Coplan <mchcopl@gmail.com>
+ ## Documentation/rev-list-options.txt ##
+@@ Documentation/rev-list-options.txt: 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=<pattern>`.
+
+ ## contrib/completion/git-completion.bash ##
+@@ contrib/completion/git-completion.bash: __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="
+
## grep.c ##
@@ grep.c: void compile_grep_patterns(struct grep_opt *opt)
- if (opt->no_body_match && opt->pattern_expression)
- opt->pattern_expression = grep_not_expr(opt->pattern_expression);
-
-- if (!header_expr)
-+ if (!header_expr || opt->header_or)
- return;
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
+@@ grep.c: 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;
## grep.h ##
@@ grep.h: struct grep_opt {
int count;
int word_regexp;
int all_match;
-+ int header_or;
++ int match_header_or_grep;
int no_body_match;
int body_hit;
#define GREP_BINARY_DEFAULT 0
@@ revision.c: static int handle_revision_opt(struct rev_info *revs, int argc, cons
revs->grep_filter.pattern_type_option = GREP_PATTERN_TYPE_PCRE;
} else if (!strcmp(arg, "--all-match")) {
revs->grep_filter.all_match = 1;
-+ // @@@ must-fix: find a better name
-+ } else if (!strcmp(arg, "--header-or")) {
-+ revs->grep_filter.header_or = 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))) {
@@ t/t7810-grep.sh: test_expect_success 'log --grep --author uses intersection' '
test_cmp expect actual
'
-+test_expect_success 'log --grep --author --header-or uses union' '
++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 --header-or --format=%s >actual &&
-+ {
-+ echo fourth && echo third
-+ } >expect &&
++ 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
+@@ t/t7810-grep.sh: 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 &&
Documentation/rev-list-options.txt | 8 ++++++++
contrib/completion/git-completion.bash | 2 +-
grep.c | 4 ++--
grep.h | 1 +
revision.c | 2 ++
t/t7810-grep.sh | 26 +++++++++++++++++++++++++-
6 files changed, 39 insertions(+), 4 deletions(-)
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 00ccf687441..db0979ac498 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=<pattern>`.
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 75193ded4bd..30fc6ed08bd 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 ac34bfeafb3..72cf599660a 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 926c0875c42..861584dba98 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 7e45f765d9f..786c229f56d 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 875dcfd98f3..c78ce150f4d 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 &&
base-commit: 7774cfed6261ce2900c84e55906da708c711d601
--
gitgitgadget
next prev parent reply other threads:[~2024-04-07 3:24 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-04-05 21:48 [PATCH] feat(log): add option to search for header or body to `git log` Max Coplan via GitGitGadget
2024-04-06 14:04 ` Phillip Wood
2024-04-07 3:24 ` Max Coplan via GitGitGadget [this message]
2024-04-07 6:08 ` [PATCH v2] log: add option to search for header or body Junio C Hamano
2024-04-07 14:00 ` Phillip Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=pull.1710.v2.git.1712460247516.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=mchcopl@gmail.com \
--cc=phillip.wood123@gmail.com \
--cc=strager.nds@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).