MCPcopy
hub / github.com/sinclairtarget/git-who

github.com/sinclairtarget/git-who @v1.3 sqlite

repository ↗ · DeepWiki ↗ · release v1.3 ↗
242 symbols 755 edges 52 files 77 documented · 32%
README

logo

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

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

Packaging status

Mac OS

$ brew install git-who

Docker

See the section on Docker below.

go install command

This method requires that you have Go installed.

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.

$ git clone git@github.com: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:

~/clones/cpython$ git who
┌─────────────────────────────────────────────────────┐
│Author                            Last Edit   Commits│
├─────────────────────────────────────────────────────┤
│Guido van Rossum                  2 mon. ago   11,213│
│Victor Stinner                    1 week ago    7,193│
│Fred Drake                        13 yr. ago    5,465│
│Georg Brandl                      1 year ago    5,294│
│Benjamin Peterson                 4 mon. ago    4,724│
│Raymond Hettinger                 1 month ago   4,235│
│Serhiy Storchaka                  3 days ago    3,366│
│Antoine Pitrou                    10 mon. ago   3,180│
│Jack Jansen                       18 yr. ago    2,978│
│Martin v. Löwis                   9 yr. ago     2,690│
│...3,026 more...                                     │
└─────────────────────────────────────────────────────┘

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

~/repos/cpython$ git who Tools/
┌─────────────────────────────────────────────────────┐
│Author                            Last Edit   Commits│
├─────────────────────────────────────────────────────┤
│Guido van Rossum                  8 mon. ago      820│
│Barry Warsaw                      1 year ago      279│
│Martin v. Löwis                   9 yr. ago       242│
│Victor Stinner                    1 month ago     235│
│Steve Dower                       1 month ago     228│
│Jeremy Hylton                     19 yr. ago      178│
│Mark Shannon                      4 hr. ago       131│
│Serhiy Storchaka                  2 mon. ago      118│
│Erlend E. Aasland                 1 week ago      117│
│Christian Heimes                  2 yr. ago       114│
│...267 more...                                       │
└─────────────────────────────────────────────────────┘

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

~/clones/cpython$ git who v3.7.1
┌─────────────────────────────────────────────────────┐
│Author                            Last Edit   Commits│
├─────────────────────────────────────────────────────┤
│Guido van Rossum                  6 yr. ago    10,986│
│Fred Drake                        13 yr. ago    5,465│
│Georg Brandl                      8 yr. ago     5,291│
│Benjamin Peterson                 6 yr. ago     4,599│
│Victor Stinner                    6 yr. ago     4,462│
│Raymond Hettinger                 6 yr. ago     3,667│
│Antoine Pitrou                    6 yr. ago     3,149│
│Jack Jansen                       18 yr. ago    2,978│
│Martin v. Löwis                   9 yr. ago     2,690│
│Tim Peters                        10 yr. ago    2,489│
│...550 more...                                       │
└─────────────────────────────────────────────────────┘

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

~/clones/cpython$ git who v3.10.9..v3.11.9
┌─────────────────────────────────────────────────────┐
│Author                            Last Edit   Commits│
├─────────────────────────────────────────────────────┤
│Miss Islington (bot)              9 mon. ago    2,551│
│Victor Stinner                    9 mon. ago      367│
│Serhiy Storchaka                  9 mon. ago      304│
│Erlend Egeberg Aasland            2 yr. ago       202│
│Christian Heimes                  2 yr. ago       200│
│Mark Shannon                      1 year ago      157│
│Irit Katriel                      10 mon. ago     135│
│Nikita Sobolev                    10 mon. ago     126│
│Pablo Galindo Salgado             1 year ago      117│
│Pablo Galindo                     9 mon. ago       97│
│...574 more...                                       │
└─────────────────────────────────────────────────────┘

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:

$ git who -l
┌──────────────────────────────────────────────────────────────────────────────┐
│Author                          Last Edit   Commits   Files        Lines (+/-)│
├──────────────────────────────────────────────────────────────────────────────┤
│Guido van Rossum                2 mon. ago   11,213  14,135     1.3m / 793,252│
│Antoine Pitrou                  10 mon. ago   3,180   3,868  944,685 / 776,587│
│Jack Jansen                     18 yr. ago    2,978   5,887  836,527 / 691,078│
│Benjamin Peterson               4 mon. ago    4,724   6,957  690,740 / 781,700│
│Georg Brandl                    1 year ago    5,294   9,139  644,620 / 640,217│
│Martin v. Löwis                 9 yr. ago     2,690   4,557  570,632 / 389,794│
│Victor Stinner                  1 week ago    7,193  11,382  464,474 / 460,396│
│Brett Cannon                    1 month ago   2,022   2,841  305,631 / 283,178│
│Serhiy Storchaka                3 days ago    3,366   9,955  335,209 / 208,899│
│Christian Heimes                1 year ago    1,553   4,191  339,706 / 178,947│
│...3,022 more...                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

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:

~/repos/cpython$ git who tree Parser/
Parser/.........................Guido van Rossum (182)
├── lexer/......................Pablo Galindo Salgado (5)
│   ├── buffer.c................Lysandros Nikolaou (1)
│   ├── buffer.h................Lysandros Nikolaou (1)
│   ├── lexer.c
│   ├── lexer.h.................Lysandros Nikolaou (1)
│   ├── state.c
│   └── state.h
├── tokenizer/..................Filipe Laíns (1)
│   ├── file_tokenizer.c
│   ├── helpers.c...............Lysandros Nikolaou (1)
│   ├── helpers.h...............Lysandros Nikolaou (1)
│   ├── readline_tokenizer.c....Lysandros Nikolaou (1)
│   ├── string_tokenizer.c......Lysandros Nikolaou (1)
│   ├── tokenizer.h.............Lysandros Nikolaou (1)
│   └── utf8_tokenizer.c........Lysandros Nikolaou (1)
├── Python.asdl.................Benjamin Peterson (14)
├── action_helpers.c............Pablo Galindo Salgado (6)
├── asdl.py.....................Benjamin Peterson (7)
├── asdl_c.py...................Benjamin Peterson (42)
├── myreadline.c
├── parser.c....................Pablo Galindo Salgado (34)
├── peg_api.c...................Lysandros Nikolaou (2)
├── pegen.c.....................Pablo Galindo (33)
├── pegen.h.....................Pablo Galindo Salgado (13)
├── pegen_errors.c..............Pablo Galindo Salgado (16)
├── string_parser.c.............Victor Stinner (10)
├── string_parser.h.............Pablo Galindo Salgado (1)
└── token.c.....................Pablo Galindo Salgado (2)

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:

~/repos/cpython$ git who tree -a Parser/
Parser/.........................Guido van Rossum (182)
├── lexer/......................Pablo Galindo Salgado (5)
│   ├── buffer.c................Lysandros Nikolaou (1)
│   ├── buffer.h................Lysandros Nikolaou (1)
│   ├── lexer.c.................Pablo Galindo Salgado (4)
│   ├── lexer.h.................Lysandros Nikolaou (1)
│   ├── state.c.................Pablo Galindo Salgado (2)
│   └── state.h.................Pablo Galindo Salgado (1)
├── pegen/......................Pablo Galindo (30)
│   ├── parse.c.................Pablo Galindo (16)
│   ├── parse_string.c..........Pablo Galindo (7)
│   ├── parse_string.h..........Pablo Galindo (2)
│   ├── peg_api.c...............Pablo Galindo (3)
│   ├── pegen.c.................Pablo Galindo (17)
│   └── pegen.h.................Pablo Galindo (9)
├── pgen/.......................Pablo Galindo (8)
│   ├── __init__.py.............Pablo Galindo (2)
│   ├── __main__.py.............Pablo Galindo (5)
│   ├── automata.py.............Pablo Galindo (4)
│   ├── grammar.py..............Pablo Galindo (5)
│   ├── keywordgen.py...........Pablo Galindo (3)
│   ├── metaparser.py...........Pablo Galindo (2)
│   ├── pgen.py.................Pablo Galindo (5)
│   └── token.py................Pablo Galindo (4)
├── tokenizer/..................Filipe Laíns (1)
│   ├── file_tokenizer.c........Filipe Laíns (1)
│   ├── helpers.c...............Lysandros Nikolaou (1)
│   ├── helpers.h...............Lysandros Nikolaou (1)
│   ├── readline_tokenizer.c....Lysandros Nikolaou (1)
│   ├── string_tokenizer.c......Lysandros Nikolaou (1)
│   ├── tokenizer.h.............Lysandros Nikolaou (1)
│   └── utf8_tokenizer.c........Lysandros Nikolaou (1)
├── .cvsignore..................Martin v. Löwis (1)
├── Makefile.in.................Guido van Rossum (10)
├── Python.asdl.................Benjamin Peterson (14)
├── acceler.c...................Guido van Rossum (17)
├── action_helpers.c............Pablo Galindo Salgado (6)
├── asdl.py.....................Benjamin Peterson (7)
├── asdl_c.py...................Benjamin Peterson (42)
├── assert.h....................Guido van Rossum (11)
├── bitset.c....................Guido van Rossum (12)
├── firstsets.c.................Guido van Rossum (13)
├── grammar.c...................Guido van Rossum (20)
...

(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 D

Extension points exported contracts — how you extend this code

Backend (Interface)
(no doc) [4 implementers]
internal/cache/cache.go

Core symbols most depended-on inside this repo

Number
called by 20
internal/format/format.go
logger
called by 18
internal/concurrent/log.go
Close
called by 16
internal/cache/cache.go
Open
called by 9
internal/cache/cache.go
logger
called by 9
internal/subcommands/log.go
logger
called by 8
internal/cache/log.go
ParseArgs
called by 8
internal/git/args.go
Wait
called by 8
internal/git/cmd/subprocess.go

Shape

Function 149
Method 64
Struct 22
TypeAlias 4
Interface 2
FuncType 1

Languages

Go100%

Modules by API surface

internal/cache/cache.go20 symbols
internal/tally/tally.go17 symbols
main.go14 symbols
internal/tally/bucket.go14 symbols
internal/concurrent/concurrent.go14 symbols
internal/cache/backends/gob.go12 symbols
internal/git/git.go11 symbols
internal/git/cmd/subprocess.go10 symbols
internal/tally/tree.go8 symbols
internal/pretty/ansi.go8 symbols
internal/git/cmd/cmd.go7 symbols
internal/cache/backends/noop.go7 symbols

Dependencies from manifests, versioned

github.com/bmatcuk/doublestar/v4v4.8.1 · 1×
github.com/mattn/go-runewidthv0.0.16 · 1×
github.com/rivo/unisegv0.2.0 · 1×
golang.org/x/sysv0.29.0 · 1×
golang.org/x/termv0.28.0 · 1×

For agents

$ claude mcp add git-who \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact