git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] git-log: added --none-match option

From
Junio C Hamano <gitster@pobox.com>
Date
Jan 12, 2015, 20:51 UTC
Message-ID
<xmqqk30r7med.fsf@gitster.dls.corp.google.com>
In-Reply-To
<xmqqk30vbm3r.fsf@gitster.dls.corp.google.com>
Junio C Hamano <gitster@pobox.com> writes:
Show 11 quoted lines
> Christoph Junghans <ottxor@gentoo.org> writes:
>
>> The only useful thing I could image is using it in conjunction with
>> --files-with-matches, but that is what --files-without-match is for.
>
> Yes, "-l" was exactly what I had in mind and I was hoping that "git
> grep -l --no-match -e WIP -e TODO -e FIXME -e NEEDSWORK" may be a
> way to find perfect files without needing any work.
>
> You can say "git grep -L -e WIP -e TODO -e FIXME -e NEEDSWORK"
> instead.  I missed that "-L" option.

Thanks for your patience. I should have realized that this not only can be "log-only" but _should_ be "log-only". As you pointed out, when we already have "-L", trying to extend it to "grep" does not make much sense.

Continuing this line of thought, as we determined that it is pointless to have this at "grep" level and it is needed only in the "log" family of commands, I would very much prefer the approach taken by your original "log --invert-grep" patch. I would further say that I prefer not to touch grep_opt at all.

The new "global-invert bit" is about "we'd run the usual grep thing on the log message, and instead of filtering to only show the commits with matching message, we only show the ones with messages that do not match". That logically belongs to the revision struct that is used to interpret what the underlying grep machinery figured out, and should not have to affect the way how underlying grep machinery works.

We would want a few test to make sure that we do not break the feature in the future changes. Here is an attempt. The patch would apply any commit your original "--invert-grep" option would have applied.

Thanks again.
-- >8 --
Subject: log: teach --invert-grep option

"git log --grep=<string>" shows only commits with messages that match the given string, but sometimes it is useful to be able to show only commits that do *not* have certain messages (e.g. "show me ones that are not FIXUP commits").

Signed-off-by: Christoph Junghans <ottxor@gentoo.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 jc: Christoph originally had the invert-grep flag in grep_opt, but
     because "git grep --invert-grep" does not make sense except in
     conjunction with "--files-with-matches", which is already
     covered by "--files-without-matches", I moved it to revisions
     structure.  I think it expresses what the feature is about
     better to have the flag there.
     When the newly inserted two tests run, the history would have
     commits with messages "initial", "second", "third", "fourth",
     "fifth", "sixth" and Second", committed in this order.  The
     first commit that does not match either "th" or "Sec" is
     "second", and "initial" is the one that does not match either
     "th" or "Sec" case insensitively.
 Documentation/rev-list-options.txt     |  4 ++++
 contrib/completion/git-completion.bash |  2 +-
 revision.c                             |  4 +++-
 revision.h                             |  2 ++
 t/t4202-log.sh                         | 12 ++++++++++++
 5 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/Documentation/rev-list-options.txt b/Documentation/rev-list-options.txt
index deb8cca..05aa997 100644
--- a/Documentation/rev-list-options.txt
+++ b/Documentation/rev-list-options.txt
@@ -66,6 +66,10 @@ if it is part of the log message.
 	Limit the commits output to ones that match all given `--grep`,
 	instead of ones that match at least one.
 
+--invert-grep::
+	Limit the commits output to ones with log message that do not
+	match the pattern specified with `--grep=<pattern>`.
+
 -i::
 --regexp-ignore-case::
 	Match the regular expression limiting patterns without regard to letter
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 06bf262..53857f0 100644
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1428,7 +1428,7 @@ __git_log_gitk_options="
 # Options that go well for log and shortlog (not gitk)
 __git_log_shortlog_options="
 	--author= --committer= --grep=
-	--all-match
+	--all-match --invert-grep
 "
 
 __git_log_pretty_formats="oneline short medium full fuller email raw format:"
diff --git a/revision.c b/revision.c
index 615535c..84b33a3 100644
--- a/revision.c
+++ b/revision.c
@@ -1952,6 +1952,8 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
 		grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter);
 	} else if (!strcmp(arg, "--all-match")) {
 		revs->grep_filter.all_match = 1;
+	} else if (!strcmp(arg, "--invert-grep")) {
+		revs->invert_grep = 1;
 	} else if ((argcount = parse_long_opt("encoding", argv, &optarg))) {
 		if (strcmp(optarg, "none"))
 			git_log_output_encoding = xstrdup(optarg);
@@ -2848,7 +2850,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
 				     (char *)message, strlen(message));
 	strbuf_release(&buf);
 	unuse_commit_buffer(commit, message);
-	return retval;
+	return opt->invert_grep ? !retval : retval;
 }
 
 static inline int want_ancestry(const struct rev_info *revs)
diff --git a/revision.h b/revision.h
index a620530..b0b82e7 100644
--- a/revision.h
+++ b/revision.h
@@ -168,6 +168,8 @@ struct rev_info {
 
 	/* Filter by commit log message */
 	struct grep_opt	grep_filter;
+	/* Negate the match of grep_filter */
+	int invert_grep;
 
 	/* Display history graph */
 	struct git_graph *graph;
diff --git a/t/t4202-log.sh b/t/t4202-log.sh
index 99ab7ca..1c9934e 100755
--- a/t/t4202-log.sh
+++ b/t/t4202-log.sh
@@ -212,6 +212,18 @@ test_expect_success 'log --grep' '
 	test_cmp expect actual
 '
 
+test_expect_success 'log --invert-grep --grep' '
+	echo second >expect &&
+	git log -1 --pretty="tformat:%s" --invert-grep --grep=th --grep=Sec >actual &&
+	test_cmp expect actual
+'
+
+test_expect_success 'log --invert-grep --grep -i' '
+	echo initial >expect &&
+	git log -1 --pretty="tformat:%s" --invert-grep -i --grep=th --grep=Sec >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success 'log --grep option parsing' '
 	echo second >expect &&
 	git log -1 --pretty="tformat:%s" --grep sec >actual &&
Previous: Junio C HamanoNext: Christoph Junghans
Message 10 of 15 in “git-log: added --invert-grep option”
  1. git-log: added --invert-grep optionChristoph Junghans, Dec 19, 2014
  2. Junio C HamanoDec 19, 2014
  3. Christoph JunghansDec 24, 2014
  4. git-log: added --grep-begin .. --grep-end syntaxChristoph Junghans, Dec 24, 2014
  5. Junio C HamanoDec 29, 2014
  6. git-log: added --none-match optionChristoph Junghans, Jan 4, 2015
  7. Junio C HamanoJan 6, 2015
  8. Christoph JunghansJan 9, 2015
  9. Junio C HamanoJan 9, 2015
  10. Junio C HamanoJan 12, 2015
  11. git-log: added --none-match optionChristoph Junghans, Jan 12, 2015
  12. log: teach --invert-grep optionChristoph Junghans, Jan 13, 2015
  13. Junio C HamanoJan 13, 2015
  14. gitk: pass --invert-grep option down to "git log"Junio C Hamano, Feb 16, 2015
  15. Paul MackerrasMar 22, 2015

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.