I want to use git log
to show all commits that do not match a given pattern. I know I can use the following to show all commits that do 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 ingrep_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'
As with thebriguy's answer, grep also has a -z option to enable it to work with null terminated strings rather than lines. This would then be as simple as inverting the match:
git log -z --color | grep -vz "bumped to version"
For safety you may want to match within the commit message only. To do this with grep, you need to use pearl expressions to match newlines within the null terminated strings. To skip the header:
git log -z | grep -Pvz '^commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'
Or with colour:
git log -z --color | \
grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*bumped to version'
Finally, if using --stat, you could also match the beginning of this output to avoid matching file names containing the commit string. So a full answer to the question would look like:
log -z --color --pretty --stat | \
grep -Pvz '^.....commit.*\nAuthor:.*\nDate:.*\n[\S\s]*?bumped to version[\S\s]*?\n [^ ]'
Note that grep -P
is described as 'highly experimental' in my man page. It may be better to use pcregrep
instead which uses libpcre, see How to give a pattern for new line in grep?. Although grep -P
works fine for me and I have no idea if pcregrep
has a -z option or equivalent.
As far as I can tell, this is not possible to do directly with a single command line; you'd have to do something like Justin Lilly suggests and then run 'git log' on the resulting list of hashes, e.g.,
git log --format="%h" | grep -v `git log -1 --grep="bumped to version" --format="%h"` > good-hashes
for h in `cat good-hashes`; do
PAGER=cat git log -1 --pretty --stat $h
done
should do the trick.
As mentioned by VonC the best option is if you can update to Git 2.4.0 (which is currently on RC2). But even if you can't do that there is no reason for elaborate scripts. A (gnu) awk one-liner should do it. git log
has the useful -z
option to separate commits by a NUL-character which makes it easy to parse them:
git log -z --pretty --stat | awk 'BEGIN{ RS="\0"; FS="\n\n" } !match($2, /<pattern>/)'
If you don't have gnu awk, you probably should at least install that. Or port this script to your specific awk version, which I leave as an exercise for the reader ;-).
A relatively simple method with a lot of flexibility is to use git log with the -z option piped to awk. The -z option adds nulls between commit records, and so makes it easy parse with awk:
git log --color=always -z | awk -v RS=\\0
(color=always is required to keep coloring when the output is a pipe). Then, its simple to add any boolean expression you want that works on each field. For example, this will print all entries where the author email is not from fugly.com, and the day of the commit was Sunday:
git log --color=always -z | awk -v RS=\\0 '!/Author:.*fugly.com>/ && /Date:.* Sun /'
Another nice thing is its you can add in any formatting option or revision range to the git log, and it still works.
One last thing, if you want to paginate it, use "less -r" to keep the colors.
EDIT: changed to use -v in awk to make it a little simpler.
git log --pretty --stat | grep -v "bumped to version"