vergenzt
vergenzt

Reputation: 10427

How to find git log messages with more than one line?

I want to use git log in a project to view only the commits that have more than one line in their commit messages (i.e. they have a longer description). What is the best way to go about this?

I tried git log --grep='\n\n', and it came up with a list of commits with more than one line, but it was not a complete list. (I went back through some of the complete log manually and quickly found commits with multiline messages that were not output by my command.)

I then also tried git log --grep='\n\r\?\n', just in case there are Windows-style line endings in some of the commits (I'm using msysgit, so it might be possible?), but it came up with the same output as the above.

Upvotes: 4

Views: 2387

Answers (2)

Aristotle Pagaltzis
Aristotle Pagaltzis

Reputation: 118138

For some extra context:

What’s happening when you use --grep='\n\n' is that \n is not special so it just means n:

You are getting the same results as with --grep='nn'.


As to your actual question:

Note that --grep splits the commit message at newlines and matches the pattern against each substring separately. This means you you cannot write a pattern for --grep that can figure out whether it’s matching against a different line than the first.

Additionally, because every commit message ends in a newline, the splitting always yields at least one completely empty substring. This means every commit matches --grep='^$'.

Therefore, there is absolutely no way of using --grep to limit git log’s output to commits with a multiline message.


So the only way of doing it is with the approach given in che’s answer. As I commented there, I suggest this particular form:

git log --format='%H%x09%x09%x09%b' \
| egrep '^[0-9a-f]{40}\t\t\t.' \
| cut -f1 \
| git log --stdin --no-walk   # or whatever

In this version, grep keeps lines that start with a commit ID followed by 3 tabs followed by any character (i.e. not followed by nothing, i.e. those are commits of interest). This pattern is extremely unlikely to appear in a commit message body, does not require a second grep to filter out commit message body lines, and the tab character also happens to be the default field delimiter for cut so that’s shorter too.

Upvotes: 0

che
che

Reputation: 12273

This seems to work for me (on Linux):

git log --pretty=format:'%H<msgst>%b<msge>' \
| fgrep -v '<msgst><msge>' | fgrep '<msgst>' | cut -b1-40 \
| git log --stdin --no-walk

Basically: print commit hashes and commit message body (minus the subject line) wrapped in some uncommon strings, exclude lines where such body is empty (e.g. commits without newlines in the messages), then take just the first lines (those with commit hash at the beginning), and print only the hashes.

Upvotes: 6

Related Questions