Subject: [PATCH] revision: add --reflog-message to grep reflog messages

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Thu, 27 Sep 2012 18:36:26 +0700

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 On Thu, Sep 27, 2012 at 2:28 AM, Junio C Hamano <[email-masked]> wrote:
 > The current commit_match() runs grep_buffer() on commit->buffer.  It
 > probably makes sense to instead notice from opt that we are running
 > log with "-g", prepare a temporary strbuf and add in the reflog
 > message to the string in commit->buffer, and run grep_buffer() on
 > that temporary strbuf on it.

 Yeah. I was starting to think that way too, otherwise combining grep
 options would be a mess. I was hoping by injecting a fake reflog
 header, we could simplify reflog exceptions in pretty.c. But it
 was not that easy.

 > I personally think it is sufficient ot just reuse --grep on
 > concatenation of commit->buffer with "Reflog message: checkout:
 > moving from as/check-ignore to pu".

 --grep only reads the commit body. So either we append reflog
 message to commit body, or we put it in the header and add a new
 option for it. I don't like appending things to the commit body as
 --grep may hit reflog message while users do not mean so.

 > If you really want to go fancier, you could add --grep-reflog option
 > that behaves like the existing --author and --committer options to
 > add "header match" elements to the grep expression, splice a fake
 > "reflog " header to the string copied from commit->buffer

 Inserting at the beginning of the commit like your demo patch works
 just fine and is simpler. I'm tempted to take the undocumented option
 name --reflog for this purpose. But it's probably not worth the risk.

 Documentation/rev-list-options.txt |  5 +++++
 grep.c                             |  1 +
 grep.h                             |  5 +++--
 revision.c                         | 19 +++++++++++++++++--
 t/t7810-grep.sh                    |  6 ++++++
 5 files changed, 32 insertions(+), 4 deletions(-)

diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index 1fc2a18..aeaa58c 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -51,6 +51,11 @@ endif::git-rev-list[]
 	commits whose author matches any of the given patterns are
 	chosen (similarly for multiple `--committer=<pattern>`).
 
+--reflog-message=<pattern>::
+	Limit the commits output to ones with reflog entries that
+	match the specified pattern (regular expression). Ignored unless
+	--walk-reflogs is given.
+
 --grep=<pattern>::
 
 	Limit the commits output to ones with log message that
diff --git a/grep.c b/grep.c
index 898be6e..72ac1bf 100644
--- a/grep.c
+++ b/grep.c
@@ -697,6 +697,7 @@ static struct {
 } header_field[] = {
 	{ "author ", 7 },
 	{ "committer ", 10 },
+	{ "reflog ", 7 },
 };
 
 static int match_one_pattern(struct grep_pat *p, char *bol, char *eol,
diff --git a/grep.h b/grep.h
index 8a28a67..1416ad7 100644
--- a/grep.h
+++ b/grep.h
@@ -29,9 +29,10 @@ enum grep_context {
 
 enum grep_header_field {
 	GREP_HEADER_AUTHOR = 0,
-	GREP_HEADER_COMMITTER
+	GREP_HEADER_COMMITTER,
+	GREP_HEADER_REFLOG,
+	GREP_HEADER_FIELD_MAX
 };
-#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1)
 
 struct grep_pat {
 	struct grep_pat *next;
diff --git a/revision.c b/revision.c
index ae12e11..837051c 100644
--- a/revision.c
+++ b/revision.c
@@ -1595,6 +1595,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 	} else if ((argcount = parse_long_opt("committer", argv, &optarg))) {
 		add_header_grep(revs, GREP_HEADER_COMMITTER, optarg);
 		return argcount;
+	} else if ((argcount = parse_long_opt("reflog-message", argv, &optarg))) {
+		add_header_grep(revs, GREP_HEADER_REFLOG, optarg);
+		return argcount;
 	} else if ((argcount = parse_long_opt("grep", argv, &optarg))) {
 		add_message_grep(revs, optarg);
 		return argcount;
@@ -2212,8 +2215,20 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 {
 	if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
 		return 1;
-	return grep_buffer(&opt->grep_filter,
-			   commit->buffer, strlen(commit->buffer));
+	if (opt->reflog_info) {
+		int retval;
+		struct strbuf buf = STRBUF_INIT;
+		strbuf_addstr(&buf, "reflog ");
+		get_reflog_message(&buf, opt->reflog_info);
+		strbuf_addch(&buf, '\n');
+		strbuf_addstr(&buf, commit->buffer);
+		retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
+		strbuf_release(&buf);
+		return retval;
+	} else {
+		return grep_buffer(&opt->grep_filter,
+				   commit->buffer, strlen(commit->buffer));
+	}
 }
 
 static inline int want_ancestry(struct rev_info *revs)
diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh
index 91db352..a0f519e 100755
--- a/t/t7810-grep.sh
+++ b/t/t7810-grep.sh
@@ -546,6 +546,12 @@ test_expect_success 'log grep (6)' '
 	test_cmp expect actual
 '
 
+test_expect_success 'log grep (7)' '
+	git log -g --reflog-message="commit: third" --pretty=tformat:%s >actual &&
+	echo third >expect &&
+	test_cmp expect actual
+'
+
 test_expect_success 'log with multiple --grep uses union' '
 	git log --grep=i --grep=r --format=%s >actual &&
 	{
-- 
1.7.12.1.406.g6ab07c4