Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
G

git-who

> 编程语言
Open source

Git blame for file trees

2.7K stars0 likes0 views
WebsiteGitHub

About

Git blame for file trees

git-who is a command-line tool for answering that eternal question:

Who wrote this code?!

Unlike git blame, which can tell you who wrote a line of code, git-who tells you the people responsible for entire components or subsystems in a codebase. You can think of git-who sort of like git blame but for file trees rather than individual files.

Demo

This README contains comprehensive documentation. For an overview, see Who Will Maintain Vim? A Demo of Git Who.

Installation

Precompiled Binaries

See releases.

Package Managers

Mac OS

bash
brew install git-who

Docker

See the section on Docker below.

go install command

This method requires that you have Go installed.

bash
go install github.com/sinclairtarget/git-who@latest

From Source

Building from source requires that you have Go, Ruby, and the rake Ruby gem installed. Note that these are only required when building from source; you can download and run one of the binary releases without installing any of these tools.

bash
git clone [email protected]:sinclairtarget/git-who.git
cd git-who
rake
./git-who --version

Usage

(In the following examples, git-who is invoked as git who. This will work automatically as long as Git can find git-who in your PATH. See the Git Alias section for more details.)

git who has three subcommands. Each subcommand gives you a different view of authorship in your Git repository.

The table Subcommand

The table subcommand is the default subcommand. You can invoke it explicitly as git who table or implicitly just as git who.

The table subcommand prints a table summarizing the contributions of every author who has made commits in the repository:

…

You can specify a path to filter the results to only commits that touched files under the given path:

…

You can also specify a branch name, tag name, or any "commit-ish" to filter the results to commits reachable from the specified commit:

…

Revision ranges also work. This shows the commits made after the release of 3.10.9 up to the release of 3.11.9:

…

Just like with git itself, when there is ambiguity between a path name and a commit-ish, you can use -- to clarify the distinction. The following command will show you contributions to the file or directory called foo even if there is also a branch called foo in your repository (or even if the file/directory was previously committed but has since been deleted):

$ git who -- foo

Options

The -m, -c, -l, and -f flags allow you to sort the table by different metrics.

The -m flag sorts the table by the "Last Edit" column, showing who edited the repository most recently. The -c flag sorts the table by first edit, so that the authors who committed to the repository earliest are at the top.

The -l flag sorts the table by number of lines modified, adding some more columns:

…

The -f flag sorts the table by the number of files modified.

There is also an -n option can be used to print more rows. Passing -n 0 prints all rows.

Run git-who table --help to see additional options for the table subcommand.

The tree Subcommand

The tree subcommand prints out a file tree showing files in the working tree just like tree. Each node in the file tree is annotated with information showing which author contributed the most to files at or under that path.

Here is an example showing contributions to the Python parser. By default, contributions will be measured by number of commits:

…

You may notice that some files, like lexer.c, are not annotated. If a file is not annotated, that is because the author who has most contributed to that file is the same as the author who has most contributed to the directory containing the file. This is done to minimize visual noise.

You can force git-who tree to annotate every file using the -a flag (for "all"). This flag also prints all file paths that were discovered while walking the commit history, including those no longer in the working tree:

…

(The above output continues but has been elided for the purposes of this README.)

Note that, whether or not the -a flag is used, commits that edited files not in the working tree will still count toward the total displayed next to ancestor directories of that file. In the above two examples, Guido van Rossum is shown as the overall highest committer to the Parser/ directory, though it takes listing the entire tree with the -a flag to see that most of his commits were to files that have since been moved or deleted.

Like with the table subcommand, you can specify a "commit-ish". This next example shows changes to the Parser/ directory that happened after the 3.10.9 release up to the 3.11.9 release.

~/clones/cpython$ git who tree v3.10.9..v3.11.9 -- Parser/
Parser/.................Pablo Galindo Salgado (52)
├── Python.asdl.........Batuhan Taskaya (1)
├── action_helpers.c....Matthieu Dartiailh (1)
├── asdl_c.py...........Batuhan Taskaya (4)
├── myreadline.c........Victor Stinner (1)
├── parser.c
├── pegen.c
├── pegen.h
├── pegen_errors.c......Miss Islington (bot) (8)
└── string_parser.c.....Miss Islington (bot) (4)

If a file isn't edited in any of the commits specified by the revision range, then it won't appear in the output of git who tree, even if the file is in the working tree. This can make git who tree useful for visualizing the changes introduced by a branch.

Options

The tree subcommand, like the table subcommand, supports the -l, -f, -m, and -c flags.

The -l flag will annotate each file tree node with the author who has added or removed the most lines at that path:

…

The -f flag will pick authors based on number of files edited. The -m flag will pick an author based on last modification time while the -c flag picks the author who first edited a file.

You can limit the depth of the tree printed by using the -d flag. The depth is measured from the current working directory.

The -a flag has already been mentioned.

Run git who tree --help to see all options available for the tree subcommand.

The hist Subcommand

The hist subcommand prints out a little bar chart / timeline of commit activity showing the history of contributions to the repository.

…

(Git was only released in 2005, so clearly there has been some version control metadata imported from another tool!)

The timeline shows the author who made the most commits in each year. The bar in the bar chart shows their contributions as a proportion of the total contributions made in that year. (The # symbol shows the proportion of total commits by the "winning" author for that year.)

Like with the other subcommands, you can filter the commits examined to just those editing files under a given path:

…

The printed timeline will begin with the date of the first commit modifying that path.

You can also filter using a commit-ish. This shows the timeline of contributions since Python's 3.12 release.

…

Options

The hist subcommand supports the -l and -f flags but not the -m or -c flags:

…

Run git who hist --help for a full listing of the options supported by the hist subcommand.

Additional Options for Filtering Commits

All of the git who subcommands take these additional options that further filter the commits that get counted.

The --author and --nauthor options allow you to specify authors to include or exclude. Both options can be specified multiple times to include or exclude multiple authors.

The --since and --until options allow you to filter out commits before or after a certain date respectively. These options each take a string that gets passed to git log to be interpreted. git log can handle some surprising inputs. See git-commit(1) for a description of what is possible.

The following example shows the paths edited by Guido van Rossum over the last eight months:

~/repos/cpython$ git who tree -d 1 --since "nine months ago" --author "Guido van Rossum"
./..................Guido van Rossum (11)
├── .github/........Guido van Rossum (2)
├── Doc/............Guido van Rossum (3)
├── Include/........Guido van Rossum (3)
├── Lib/............Guido van Rossum (1)
├── Modules/........Guido van Rossum (1)
├── Objects/........Guido van Rossum (1)
├── PCbuild/........Guido van Rossum (2)
├── Programs/.......Guido van Rossum (1)
├── Python/.........Guido van Rossum (4)
├── Tools/..........Guido van Rossum (1)
├── configure
└── configure.ac

If you want to filter out all commits under a certain path or using a certain extension (i.e. ignore these files), you can do so using Git's "exclude" pathspec magic.

The following example counts all files under the Parser/ directory but excludes .c files:

~/clones/cpython$ git who tree -- Parser ':!*.c'
Parser/...................Benjamin Peterson (56)
├── lexer/................Pablo Galindo Salgado (1)
│   ├── buffer.h..........Lysandros Nikolaou (1)
│   ├── lexer.h...........Lysandros Nikolaou (1)
│   └── state.h
├── tokenizer/............Lysandros Nikolaou (1)
│   ├── helpers.h
│   └── tokenizer.h
├── Python.asdl
├── asdl.py
├── asdl_c.py
├── pegen.h...............Pablo Galindo Salgado (14)
└── string_parser.h.......Pablo Galindo Salgado (1)

Git supports other kinds of pathspec magic but the "exclude" pathspec magic is the only one supported by git who.

Caching

git who caches data on a per-repository basis under XDG_CACHE_HOME (this is ~/.cache if the environment variable is not set).

You can disable caching by setting GIT_WHO_DISABLE_CACHE=1.

Git Alias

If you install the git-who binary somewhere in your path, running git who will automatically invoke it with no further configuration. This is a Git feature.

If you install the binary using a different name or just like to be explicit you can configure a Git alias in your global Git config like so:

[alias]
    who = "!git-who-executable-name"

See here for more information about Git aliases.

Git Mailmap

Quite often, people end up committing to a repository under different names or using different email addresses. For example, someone might make a commit using the name "Nathan Smith" and their work email address and then later make a commit using the name "Nate Smith" and their personal email address.

How can you make sure that all of someone's commits are counted together instead of being attributed to three or four different people with slightly different names?

Git already has a solution for this problem called Git mailmap. If a .mailmap file is present in a Git repository, git who will respect it.

Git Blame Ignore Revs

If you have a .git-blame-ignore-revs file at the root of your repository, git who will skip all commits named in that file. The format of the file should be identical to the format of the file expected by the --ignore-revs-file option of git blame.

Note that git who will not consult the value of blame.ignoreRevsFile in your Git configuration. If there is a file named .git-blame-ignore-revs at the root of your repository, git who will use it. Otherwise no commits will be skipped.

Using Docker

You can run git-who as a Docker container without installing it on your system directly. Follow these steps to build and use the Docker image.

Building the Docker Image

To build the git-who Docker image, run the following command from

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Go

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言