How to invert `git log –grep=` or How to show git logs that don’t match a pattern

This will be possible with Git 2.4+ (Q2 2015): see commit 22dfa8a by Christoph Junghans (junghans):

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”).

Originally, we 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“, it was moved it to revisions structure.
To have the flag there expresses the function to the feature better.

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 commits that does not match either “th” or “Sec” is “second” and “initial“. For the case insensitive case only “initial” matches.

--invert-grep

Limit the commits output to ones with log message that do not match the pattern specified with --grep=<pattern>.

Example:

I first grep message with “sequencer” in them:

vonc@voncm C:\Users\vonc\prog\git\git

> git log -2 --pretty="tformat:%s" --grep=sequencer
Merge branch 'js/sequencer-wo-die'
sequencer: ensure to release the lock when we could not read the index

If I want messages with no sequencer:

> git log -2 --pretty="tformat:%s" --grep=sequencer --invert-grep
Second batch for 2.11
Merge branch 'js/git-gui-commit-gpgsign'

Warning: this inverts only patterns specified by --grep.
It will not invert anymore header matches, like --author, --committer, starting Git 2.35+ (Q1 2022).
See an example in “equivalence of: git log --exclude-author?“.


Note that git -P log -1 --invert-grep could segfault:

Giving “--invert-grep” and “--all-match” without “--grep” to the “git log(man) command resulted in an attempt to access grep pattern expression structure that has not been allocated, which has been corrected with Git 2.39 (Q4 2022).

See commit db84376 (11 Oct 2022) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano — gitster in commit 91d3d7e, 21 Oct 2022)

grep.c: remove “extended” in favor of "pattern_expression", fix segfault

Reported-by: orygaw
Signed-off-by: Ævar Arnfjörð Bjarmason

Since 79d3696 (“git-grep: boolean expression on pattern matching.”, 2006-06-30, Git v1.4.2-rc1 — merge) the "pattern_expression" member has been used for complex queries (AND/OR…), with "pattern_list" being used for the simple OR queries.
Since then we’ve used both "pattern_expression" and its associated boolean “extended” member to see if we have a complex expression.

Since f41fb66 (revisions API: have release_revisions() release , 2022-04-13, Git v2.37.0-rc0 — merge listed in batch #8) (revisions API: have release_revisions() release "grep_filter", 2022-04-13) we’ve had a subtle bug relating to that: If we supplied options that were only used for “complex queries”, but didn’t supply the query itself we’d set "opt->extended", but would have a NULL "pattern_expression".
As a result these would segfault as we tried to call “free_grep_patterns()” from "release_revisions()“:

git -P log -1 --invert-grep
git -P log -1 --all-match

The root cause of this is that we were conflating the state management we needed in “compile_grep_patterns()” itself with whether or not we had an "opt->pattern_expression" later on.

In this cases as we’re going through “compile_grep_patterns()” we have no "opt->pattern_list" but have "opt->no_body_match" or "opt->all_match".
So we’d set "opt->extended = 1″, but not “return” on "opt->extended" as that’s an “else if” in the same “if” statement.

That behavior is intentional and required, as the common case is that we have an "opt->pattern_list" that we’re about to parse into the "opt->pattern_expression".

But we don’t need to keep track of this “extended” flag beyond the state management in compile_grep_patterns() itself.
It needs it, but once we’re out of that function we can rely on "opt->pattern_expression" being non-NULL instead for using these extended patterns.

Leave a Comment