Git Log by Author

📜Part of the Git and Windows tooling notes on this site. For the PowerShell side, see the PowerShell Complete Guide.
The short answer

git log --author="Name". It is a regular expression matched against the whole Name <email> string, so partial names work and --author="^Name$" matches nothing.

Finding one person’s commits is a common enough job: reviewing a colleague’s work, working out who touched something, or counting contributions. git log --author does it, with one behaviour that catches people out.

Filtering By Author

git log --author="Sam"
git log --author="Sam" --oneline

That returns every commit whose author matches. The match is partial by default, so --author="Sam" also matches “Samantha” and “Sam Taylor”.

It Is A Regex, And It Matches More Than The Name

This is the part worth knowing, because it makes an obvious-looking command silently return nothing.

--author is matched against the author as Git stores it, which is the name and the email together in one string:

Sam Taylor <sam.taylor@example.com>
Anchoring with $ returns zero commits. git log --author="^Sam Taylor$" looks like it should match exactly, and it matches nothing at all, because the string does not end after the name. Tested on a repository with 777 commits by one author: --author="^Name$" returned 0, while --author="^Name <" returned all 777.

So anchor at the start and stop before the email, or match on the email instead:

git log --author="^Sam Taylor <"     # exact name, anchored properly
git log --author="@example.com"        # everyone from one organisation
git log -i --author="sam"              # case-insensitive

-i makes the match case-insensitive. Order does not matter: -i --author="sam" and --author="sam" -i both work.

Counting Commits Per Person

For a quick tally, do not loop over git log. There is a built-in:

git shortlog -sn
git shortlog -sn --all        # include every branch
   412  Sam Taylor
   238  R. Maintainer
    77  A. Developer

-s summarises to counts only and -n sorts by number of commits. Without them you get the full list of commit subjects grouped by author, which is also useful for writing release notes.

Commit counts are a measure of how someone commits, not how much they contribute. Someone who squashes their work into one commit per feature will always look less active than someone who commits every few minutes. Worth remembering before anyone uses this in a review.

Combining With Other Filters

git log --author="Sam" --since="1 month ago" --oneline
git log --author="Sam" --oneline -- src/reports/     # one directory
git log --author="Sam" --grep="fix" -i --oneline     # their fixes only

For the one-line format itself and the alias worth saving, see git log one line.

Author Versus Committer

Git records two people per commit. The author wrote the change, the committer applied it. They differ after a rebase, a cherry-pick, or when someone applies a patch on your behalf. --author filters the first, --committer the second, and if a search comes back empty when you are certain the person worked on something, try the other one.

If SQL Server is part of your day job, my current work lives over at sqldba.blog: production DBA scripts, an error library and the SSMS guide.

It Returned Nothing and the Person Definitely Exists

Two causes, and neither of them produces an error. You get an empty result and no reason for it.

Alternation does not work in the default regex flavour. --author uses basic regular expressions unless you say otherwise, and in that mode | is a literal pipe character rather than an “or”. So the obvious way to search for two people silently matches nobody. Tested on git 2.54.0:

# returns 0 commits, with no error
git log --author='Sam Taylor|Ann Other'

# returns them, because -E turns on extended regex
git log -E --author='Sam Taylor|Ann Other'

This is the same shape of trap as the anchoring one further up the page. The command looks correct, exits cleanly, and is quietly answering a different question.

Or you are looking at the wrong part of history. git log walks back from HEAD, so commits sitting on a branch that has never been merged are simply not in scope. Somebody who has worked only on an unmerged feature branch shows zero commits, which reads exactly like “this person has not contributed”:

# 0 commits, because their branch is not merged
git log --author='Branch Person' --oneline

# 1 commit, because --all covers every ref
git log --all --author='Branch Person' --oneline

If you are auditing rather than browsing, use --all. Both of those results are from the same repository, seconds apart.

Asking About Several People at Once

You do not need the regex for this. Repeating --author ORs the filters, which is usually what you meant and is far easier to read:

git log --author='Sam Taylor' --author='Ann Other' --oneline

Worth knowing it is an OR and not an AND, in case you were hoping to narrow rather than widen. There is no combination of --author flags that means “commits by both of these people”, because a commit only has one author.

One Person, Several Identities

This is the one that quietly ruins counts. A single person routinely commits under a work email, a personal email, and GitHub’s 12345+user@users.noreply.github.com address, which gets applied to squash merges when they have email privacy switched on. Filtering by name misses some of those. Filtering by email misses others.

The fix is a .mailmap file at the root of the repository, mapping the stray identities onto one canonical one:

# .mailmap
Sam Taylor <sam@example.com> <sam.taylor@oldjob.com>
Sam Taylor <sam@example.com> <12345+sam@users.noreply.github.com>

The catch is that git log and git shortlog do not treat that file the same way. Tested on 2.54.0 with the mapping above in place: git shortlog -sn collapsed both identities into one person automatically, while git log --format='%an' still listed both names. So the tally and the raw log disagree about the same human being, and neither is wrong.

Two ways to make the log agree with the tally:

# %aN, capital N, is the mailmap-aware placeholder
git log --format='%aN'

# --use-mailmap also makes --author match the mapped identities
git log --use-mailmap --author='Sam Taylor' --oneline

That second one matters more than it looks: with the mapping in place it returned the old-identity commits too, which is exactly what you want when somebody changed employer halfway through a project.

Two Things That Bite Inside Scripts

git shortlog with no revision range reads standard input. Interactively you will see it sit there doing nothing. In a scheduled job with stdin closed it is worse than that: it returns successfully with no output at all, so your report is empty and the exit code says everything went fine. Tested on 2.54.0, and I managed to hang a terminal on it while writing this section. Always give it something to walk:

# hangs, or returns nothing at all
git shortlog -sn

# does what you meant
git shortlog -sn HEAD
git shortlog -sn --all

Counting with -sn includes merge commits. On a repository that takes pull requests this inflates whoever does the merging, because every PR they merged counts as one of their commits. If you are counting contribution rather than activity, exclude them:

git shortlog -sn --no-merges --all

And the small one that catches everybody once: git pipes output through a pager, so a git log in a script can stall waiting for a reader that does not exist. git --no-pager log ... removes the problem.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Looking for SQL Server?

This site started as a SQL Server blog in 2017 and the archive is still here. The new SQL Server writing, and all the scripts, moved to a site of their own.

sqldba.blogScripts, error library, wait types, SSMS
Browse by topic