How to Sort Git Commits by Author Date
Post by
on January 9, 2013Git commits have both a Commit Date and an Author Date. As Alex Peattie explains, the Commit Date is date time when the commit was added to the current branch and Author Date is when the author actually wrote the first commit message. By default, Git orders the git log by the Commit Date, but shows the Author Date in the commit's message.
There are times when you want to order the git log by the Author Date instead of the Commit Date. Long story short, there is no way to do this in Git. However, after scouring the internet I found a number of solutions that worked and didn't work. (Scroll to the bottom for my final solution.)
Solution 1: Git Log --stdin Flag
Source: http://stackoverflow.com/a/13799883
This solution doesn't work. Git still lists them in order of Commit Date, so I'm not sure what this guy was talking about.
$ git log --pretty="format:%at %H" | sort | sed 's/.* //' | git log --stdin
Solution 2: While Loop
Source: http://linuxshellaccount.blogspot.com/2008/08/using-bash-to-feed-command-output-to.html
I was playing around with the idea of writing a for loop to loop through the sorted hashes and run a git log when I came accross the above thread. The result works, but it dumps everything to standard output which you can't pipe to less unless you make it into a script, which is fine, but not simple enough.
$ while read line; do git log -1 $line; echo ""; done < <(git log --pretty="format:%at %H" | sort -r | sed 's/.* //')
Solution 3: Sort One Line Output
Next, I decided that I would have to be okay with not having anything more than a one line output. That simplifies things significantly, so I wrote this:
$ git log --date=short --pretty="format:%at %H %ad | %s [%an]" | sort -r | cut -d" " -f2- | less
Note: change the date value of "short" to "iso" or "rfc" to get different date formats.
Solution 4: Sort Using awk
I know that awk is a powerful tool and you can probably sort a git log using it, but the learning curve would be too high for me. Thus, I skipped awk as a solution.
Solution 5 (final): Sort One Line Output and Replace Line Endings
Then, I got a brilliant idea: just replace the line endings! The pretty flag has the ability to add line endings using "%n", but the obvious issue is that sort only works on a line-by-line basis. So, I decided to add "\n" as a placeholder and replace it later.
Version 1.0: Use a Bash Hack for New Line Character
Replacing "\n" with a real line ending is more complex than I could have imagined. After many of my own attempts and reading an absurdly long thread on Stack Overflow about it, I finally found the following solution on an old Linux Questions thread from 2004:
$ git log --pretty="format:%at commit %H\nAuthor: %an <%ae>\nDate: %aD\n\n %s\n" | sort -r | cut -d" " -f2- | sed -e 's/\\n/\ /g'
Version 2.0: Use Echo for New Line Character
The only problem with the 1.0 solution is that it requires the line break be inserted, thus it is a two-line command. I figured there HAD to be a way to add a silly line return. Fortunately, on that same thread, I saw an interesting solution: use echo.
$ git log --pretty="format:%at commit %H\nAuthor: %an <%ae>\nDate: %aD\n\n %s\n" | sort -r | cut -d" " -f2- | sed -e "s/\\\n/\\`echo -e '\n\r'`/g" | less
Version 3.0: Remove the ^M
The 2.0 solution works great! But, we have a minor issue. Now, less is showing a silly carriage return character in the output. After many failed attempts and much time spent scouring the internet, once again, I found a genius solution by Indiana University: tr -d '\15\32'.
$ git log --pretty="format:%at commit %H\nAuthor: %an <%ae>\nDate: %aD\n\n %s\n" | sort -r | cut -d" " -f2- | sed -e "s/\\\n/\\`echo -e '\n\r'`/g" | tr -d '\15\32' | less
Version 4.0: Add Color
Finally, to complete the script, I had to add color. The convenient part of this is that the pretty flag supports some default colors, so it was as simple as adding %C(yellow) and %Creset.
$ git log --pretty="format:%at commit %C(yellow)%H%Creset\nAuthor: %an <%ae>\nDate: %aD\n\n %s\n" | sort -r | cut -d" " -f2- | sed -e "s/\\\n/\\`echo -e '\n\r'`/g" | tr -d '\15\32' | less -R
And, notice that we have added the "R" flag to less; this allows less to interpret the color, thanks to a ServerFault comment for pointing that out.
UPDATE: I have added a set of tools, including this one, to the "Git Extras" GitHub repository.