Subject: [PATCH] revision: add --reflog-message=<pattern> to grep reflog messages

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Wed, 26 Sep 2012 19:12:45 +0700

Both "git log" and "git reflog show" recognize this option.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 Itch: how to show reflogs for checkout operation only?

 Instead of ignoring when -g is not given, we might want to imply -g.

 Still itch: grep highlight! For all applicable areas: commit headers
 including reflog messages, commit body, diff.

 Documentation/rev-list-options.txt |  5 +++++
 revision.c                         | 30 ++++++++++++++++++++++++++++++
 revision.h                         |  1 +
 3 files changed, 36 insertions(+)

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 messages 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/revision.c b/revision.c
index ae12e11..ee55bb2 100644
--- a/revision.c
+++ b/revision.c
@@ -1053,6 +1053,11 @@ void init_revisions(struct rev_info *revs, const char *prefix)
 	revs->grep_filter.header_tail = &(revs->grep_filter.header_list);
 	revs->grep_filter.regflags = REG_NEWLINE;
 
+	revs->reflog_filter.status_only = 1;
+	revs->reflog_filter.pattern_tail = &(revs->reflog_filter.pattern_list);
+	revs->reflog_filter.header_tail = &(revs->reflog_filter.header_list);
+	revs->reflog_filter.regflags = REG_NEWLINE;
+
 	diff_setup(&revs->diffopt);
 	if (prefix && !revs->diffopt.prefix) {
 		revs->diffopt.prefix = prefix;
@@ -1298,6 +1303,12 @@ static void add_message_grep(struct rev_info *revs, const char *pattern)
 	add_grep(revs, pattern, GREP_PATTERN_BODY);
 }
 
+static void add_reflog_grep(struct rev_info *revs, const char *ptn)
+{
+	append_grep_pattern(&revs->reflog_filter, ptn,
+			    "command line", 0, GREP_PATTERN);
+}
+
 static int handle_revision_opt(struct rev_info *revs, int argc, const char **argv,
 			       int *unkc, const char **unkv)
 {
@@ -1600,15 +1611,23 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		return argcount;
 	} else if (!strcmp(arg, "--grep-debug")) {
 		revs->grep_filter.debug = 1;
+	} else if ((argcount = parse_long_opt("reflog-message",
+					      argv, &optarg))) {
+		add_reflog_grep(revs, optarg);
+		return argcount;
 	} else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) {
 		revs->grep_filter.regflags |= REG_EXTENDED;
+		revs->reflog_filter.regflags |= REG_EXTENDED;
 	} else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) {
 		revs->grep_filter.regflags |= REG_ICASE;
+		revs->reflog_filter.regflags |= REG_ICASE;
 		DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE);
 	} else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) {
 		revs->grep_filter.fixed = 1;
+		revs->reflog_filter.fixed = 1;
 	} else if (!strcmp(arg, "--all-match")) {
 		revs->grep_filter.all_match = 1;
+		revs->reflog_filter.all_match = 1;
 	} else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
 		if (strcmp(optarg, "none"))
 			git_log_output_encoding = xstrdup(optarg);
@@ -1891,6 +1910,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
 	diff_setup_done(&revs->diffopt);
 
 	compile_grep_patterns(&revs->grep_filter);
+	compile_grep_patterns(&revs->reflog_filter);
 
 	if (revs->reverse && revs->reflog_info)
 		die("cannot combine --reverse with --walk-reflogs");
@@ -2242,6 +2262,16 @@ enum commit_action get_commit_action(struct rev_info *revs, struct commit *commi
 		    ((revs->max_parents >= 0) && (n > revs->max_parents)))
 			return commit_ignore;
 	}
+	if (revs->reflog_info &&
+	    revs->reflog_filter.pattern_list) {
+		struct strbuf sb = STRBUF_INIT;
+		int ignore;
+		get_reflog_message(&sb, revs->reflog_info);
+		ignore = !grep_buffer(&revs->reflog_filter, sb.buf, sb.len);
+		strbuf_release(&sb);
+		if (ignore)
+			return commit_ignore;
+	}
 	if (!commit_match(commit, revs))
 		return commit_ignore;
 	if (revs->prune && revs->dense) {
diff --git a/revision.h b/revision.h
index a95bd0b..0ebe34b 100644
--- a/revision.h
+++ b/revision.h
@@ -145,6 +145,7 @@ struct rev_info {
 
 	/* Filter by commit log message */
 	struct grep_opt	grep_filter;
+	struct grep_opt	reflog_filter;
 
 	/* Display history graph */
 	struct git_graph *graph;
-- 
1.7.12.1.406.g6ab07c4