From ad4813b3c2513c5dc7e84305ab8a393b32124977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 29 Sep 2012 11:41:27 +0700 Subject: [PATCH 1/4] grep: prepare for new header field filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grep supports only author and committer headers, which have the same special treatment that later headers may or may not have. Check for field type and only strip_timestamp() when the field is either author or committer. GREP_HEADER_FIELD_MAX is put in the grep_header_field enum to be calculated automatically, correctly, as long as it's at the end of the enum. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- grep.c | 9 ++++++++- grep.h | 6 ++++-- t/t7810-grep.sh | 12 ++++++++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/grep.c b/grep.c index 898be6ebf..8d73995e8 100644 --- a/grep.c +++ b/grep.c @@ -720,7 +720,14 @@ static int match_one_pattern(struct grep_pat *p, char *bol, char *eol, if (strncmp(bol, field, len)) return 0; bol += len; - saved_ch = strip_timestamp(bol, &eol); + switch (p->field) { + case GREP_HEADER_AUTHOR: + case GREP_HEADER_COMMITTER: + saved_ch = strip_timestamp(bol, &eol); + break; + default: + break; + } } again: diff --git a/grep.h b/grep.h index 8a28a676f..d54adbe56 100644 --- a/grep.h +++ b/grep.h @@ -29,9 +29,11 @@ enum grep_context { enum grep_header_field { GREP_HEADER_AUTHOR = 0, - GREP_HEADER_COMMITTER + GREP_HEADER_COMMITTER, + + /* Must be at the end of the enum */ + GREP_HEADER_FIELD_MAX }; -#define GREP_HEADER_FIELD_MAX (GREP_HEADER_COMMITTER + 1) struct grep_pat { struct grep_pat *next; diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 91db352cc..30eaa9a54 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -628,6 +628,18 @@ test_expect_success 'log --all-match --grep --grep --author takes intersection' test_cmp expect actual ' +test_expect_success 'log --author does not search in timestamp' ' + : >expect && + git log --author="$GIT_AUTHOR_DATE" >actual && + test_cmp expect actual +' + +test_expect_success 'log --committer does not search in timestamp' ' + : >expect && + git log --committer="$GIT_COMMITTER_DATE" >actual && + test_cmp expect actual +' + test_expect_success 'grep with CE_VALID file' ' git update-index --assume-unchanged t/t && rm t/t && From 72fd13f71c18b438ca3e482c126bcbcaa2dac650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 29 Sep 2012 11:41:28 +0700 Subject: [PATCH 2/4] revision: add --grep-reflog to filter commits by reflog messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to --author/--committer which filters commits by author and committer header fields. --grep-reflog adds a fake "reflog" header to commit and a grep filter to search on that line. All rules to --author/--committer apply except no timestamp stripping. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/rev-list-options.txt | 8 ++++++++ grep.c | 1 + grep.h | 1 + revision.c | 20 ++++++++++++++++++-- t/t7810-grep.sh | 26 ++++++++++++++++++++++++++ 5 files changed, 54 insertions(+), 2 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index 1fc2a1840..aa7cd9dcf 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -51,6 +51,14 @@ endif::git-rev-list[] commits whose author matches any of the given patterns are chosen (similarly for multiple `--committer=`). +--grep-reflog=:: + + Limit the commits output to ones with reflog entries that + match the specified pattern (regular expression). With + more than one `--grep-reflog`, commits whose reflog message + matches any of the given patterns are chosen. Ignored unless + `--walk-reflogs` is given. + --grep=:: Limit the commits output to ones with log message that diff --git a/grep.c b/grep.c index 8d73995e8..d70dcdf0e 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 d54adbe56..6e78b96a2 100644 --- a/grep.h +++ b/grep.h @@ -30,6 +30,7 @@ enum grep_context { enum grep_header_field { GREP_HEADER_AUTHOR = 0, GREP_HEADER_COMMITTER, + GREP_HEADER_REFLOG, /* Must be at the end of the enum */ GREP_HEADER_FIELD_MAX diff --git a/revision.c b/revision.c index ae12e11fb..109bec144 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("grep-reflog", 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; @@ -2210,10 +2213,23 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit) static int commit_match(struct commit *commit, struct rev_info *opt) { + int retval; + struct strbuf buf = STRBUF_INIT; 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) { + strbuf_addstr(&buf, "reflog "); + get_reflog_message(&buf, opt->reflog_info); + strbuf_addch(&buf, '\n'); + strbuf_addstr(&buf, commit->buffer); + } + if (buf.len) + retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len); + else + retval = grep_buffer(&opt->grep_filter, + commit->buffer, strlen(commit->buffer)); + strbuf_release(&buf); + return retval; } static inline int want_ancestry(struct rev_info *revs) diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 30eaa9a54..3a5d0fd77 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -546,6 +546,32 @@ test_expect_success 'log grep (6)' ' test_cmp expect actual ' +test_expect_success 'log grep (7)' ' + git log -g --grep-reflog="commit: third" --pretty=tformat:%s >actual && + echo third >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (8)' ' + git log -g --grep-reflog="commit: third" --grep-reflog="commit: second" --pretty=tformat:%s >actual && + { + echo third && echo second + } >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (9)' ' + git log -g --grep-reflog="commit: third" --author="Thor" --pretty=tformat:%s >actual && + echo third >expect && + test_cmp expect actual +' + +test_expect_success 'log grep (9)' ' + git log -g --grep-reflog="commit: third" --author="non-existant" --pretty=tformat:%s >actual && + : >expect && + test_cmp expect actual +' + test_expect_success 'log with multiple --grep uses union' ' git log --grep=i --grep=r --format=%s >actual && { From baa6378ff2106738c74213280904507d0ed8129c Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 29 Sep 2012 11:59:52 -0700 Subject: [PATCH 3/4] log --grep-reflog: reject the option without -g Signed-off-by: Junio C Hamano --- Documentation/rev-list-options.txt | 4 ++-- grep.c | 2 ++ grep.h | 1 + revision.c | 13 +++++++++++-- t/t7810-grep.sh | 4 ++++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index aa7cd9dcf..ca221060d 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -56,8 +56,8 @@ endif::git-rev-list[] Limit the commits output to ones with reflog entries that match the specified pattern (regular expression). With more than one `--grep-reflog`, commits whose reflog message - matches any of the given patterns are chosen. Ignored unless - `--walk-reflogs` is given. + matches any of the given patterns are chosen. It is an + error to use this option unless `--walk-reflogs` is in use. --grep=:: diff --git a/grep.c b/grep.c index d70dcdf0e..edc777667 100644 --- a/grep.c +++ b/grep.c @@ -64,6 +64,8 @@ void append_header_grep_pattern(struct grep_opt *opt, { struct grep_pat *p = create_grep_pat(pat, strlen(pat), "header", 0, GREP_PATTERN_HEAD, field); + if (field == GREP_HEADER_REFLOG) + opt->use_reflog_filter = 1; do_append_grep_pat(&opt->header_tail, p); } diff --git a/grep.h b/grep.h index 6e78b96a2..c256ac6e1 100644 --- a/grep.h +++ b/grep.h @@ -107,6 +107,7 @@ struct grep_opt { #define GREP_BINARY_TEXT 2 int binary; int extended; + int use_reflog_filter; int pcre; int relative; int pathname; diff --git a/revision.c b/revision.c index 109bec144..9f5e9df93 100644 --- a/revision.c +++ b/revision.c @@ -1908,6 +1908,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s if (revs->reflog_info && revs->graph) die("cannot combine --walk-reflogs with --graph"); + if (!revs->reflog_info && revs->grep_filter.use_reflog_filter) + die("cannot use --grep-reflog without --walk-reflogs"); return left; } @@ -2217,12 +2219,19 @@ static int commit_match(struct commit *commit, struct rev_info *opt) struct strbuf buf = STRBUF_INIT; if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list) return 1; - if (opt->reflog_info) { + + /* Prepend "fake" headers as needed */ + if (opt->grep_filter.use_reflog_filter) { strbuf_addstr(&buf, "reflog "); get_reflog_message(&buf, opt->reflog_info); strbuf_addch(&buf, '\n'); - strbuf_addstr(&buf, commit->buffer); } + + /* Copy the commit to temporary if we are using "fake" headers */ + if (buf.len) + strbuf_addstr(&buf, commit->buffer); + + /* Find either in the commit object, or in the temporary */ if (buf.len) retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len); else diff --git a/t/t7810-grep.sh b/t/t7810-grep.sh index 3a5d0fd77..f698001c9 100755 --- a/t/t7810-grep.sh +++ b/t/t7810-grep.sh @@ -572,6 +572,10 @@ test_expect_success 'log grep (9)' ' test_cmp expect actual ' +test_expect_success 'log --grep-reflog can only be used under -g' ' + test_must_fail git log --grep-reflog="commit: third" +' + test_expect_success 'log with multiple --grep uses union' ' git log --grep=i --grep=r --format=%s >actual && { From 38cfe915bfc3ea0dbcbedaa82c44460a2ada2f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20Th=C3=A1i=20Ng=E1=BB=8Dc=20Duy?= Date: Sat, 29 Sep 2012 11:41:29 +0700 Subject: [PATCH 4/4] revision: make --grep search in notes too if shown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Notes are shown after commit body. From user perspective it looks pretty much like commit body and they may assume --grep would search in that part too. Make it so. Signed-off-by: Nguyễn Thái Ngọc Duy Signed-off-by: Junio C Hamano --- Documentation/rev-list-options.txt | 3 +++ revision.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt index ca221060d..ee497430c 100644 --- a/Documentation/rev-list-options.txt +++ b/Documentation/rev-list-options.txt @@ -66,6 +66,9 @@ endif::git-rev-list[] more than one `--grep=`, commits whose message matches any of the given patterns are chosen (but see `--all-match`). ++ +When `--show-notes` is in effect, the message from the notes as +if it is part of the log message. --all-match:: Limit the commits output to ones that match all given --grep, diff --git a/revision.c b/revision.c index 9f5e9df93..a09e60bed 100644 --- a/revision.c +++ b/revision.c @@ -2231,6 +2231,14 @@ static int commit_match(struct commit *commit, struct rev_info *opt) if (buf.len) strbuf_addstr(&buf, commit->buffer); + /* Append "fake" message parts as needed */ + if (opt->show_notes) { + if (!buf.len) + strbuf_addstr(&buf, commit->buffer); + format_display_notes(commit->object.sha1, &buf, + get_log_output_encoding(), 0); + } + /* Find either in the commit object, or in the temporary */ if (buf.len) retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);