{"id":30141033,"url":"https://github.com/trinhminhtriet/git-author","last_synced_at":"2025-08-11T04:22:24.691Z","repository":{"id":284948125,"uuid":"956303067","full_name":"trinhminhtriet/git-author","owner":"trinhminhtriet","description":"🔍 git-author – Identify codebase authorship at a component level, beyond git blame, for better ownership insights.","archived":false,"fork":false,"pushed_at":"2025-07-29T08:25:16.000Z","size":68,"stargazers_count":5,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-29T10:39:05.756Z","etag":null,"topics":["code-analysis","code-ownership","git-blame","git-history","git-statistics","git-tools","repository-analysis","repository-insights"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trinhminhtriet.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-03-28T03:03:37.000Z","updated_at":"2025-07-29T08:24:03.000Z","dependencies_parsed_at":"2025-03-28T15:24:05.325Z","dependency_job_id":"d9ecc709-b33b-4b8f-b8cb-2bf77754b5fd","html_url":"https://github.com/trinhminhtriet/git-author","commit_stats":null,"previous_names":["trinhminhtriet/git-author"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/trinhminhtriet/git-author","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trinhminhtriet%2Fgit-author","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trinhminhtriet%2Fgit-author/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trinhminhtriet%2Fgit-author/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trinhminhtriet%2Fgit-author/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trinhminhtriet","download_url":"https://codeload.github.com/trinhminhtriet/git-author/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trinhminhtriet%2Fgit-author/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269829378,"owners_count":24481920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-11T02:00:10.019Z","response_time":75,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-analysis","code-ownership","git-blame","git-history","git-statistics","git-tools","repository-analysis","repository-insights"],"created_at":"2025-08-11T04:22:23.446Z","updated_at":"2025-08-11T04:22:24.655Z","avatar_url":"https://github.com/trinhminhtriet.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# git-author\n\n🔍 **git-author** – Identify Who Owns Your Codebase\n\n`git-author` is a command-line tool designed to answer the age-old question:\n\n\u003e _Who wrote this code?!_\n\nUnlike `git blame`, which pinpoints who wrote a specific **line** of code, `git-author` provides a **big-picture view** of authorship. It analyzes your Git repository to determine **who contributed to entire components, directories, or subsystems**, helping teams understand **code ownership at a structural level**.\n\nThink of `git-author` as `git blame` for **file trees** rather than individual lines—perfect for tracking ownership, reviewing contributions, and improving collaboration in large codebases. 🚀\n\n## Features\n\n- 📊 **Authorship Insights** – Get a summary of contributions per author across the entire repository.\n- 🏗 **Flexible Analysis** – Supports different views of authorship with multiple subcommands (`table`, `top`, etc.).\n- 🚀 **Fast \u0026 Efficient** – Optimized for performance, even in large repositories.\n- 🛠 **Seamless Git Integration** – Works alongside existing Git workflows and aliases.\n- 💡 **Cross-Platform** – Runs on macOS, Linux, and Windows.\n- 📦 **Easy Installation** – Available via package managers (`brew`, AUR) or precompiled binaries.\n- 🛠 **Build from Source** – Simple setup for developers who want to customize or contribute.\n\nLet me know if you'd like any refinements! 🚀\n\n## 🚀 Installation\n\n### Precompiled Binaries\n\nSee [releases](https://github.com/trinhminhtriet/git-author/releases).\n\n### From Source\n\nBuilding from source requires that you have Go, Ruby, and the `rake` Ruby gem\ninstalled. Note that these are _only_ required when building from source; you\ncan download and run one of the binary releases without installing any of these\ntools.\n\n```sh\n$ git clone git@github.com:trinhminhtriet/git-author.git\n$ cd git-author\n$ rake\n$ ./git-author --version\n```\n\n## Usage\n\n_(In the following examples, `git-author` is invoked as `git author`. This will work\nautomatically as long as Git can find `git-author` in your PATH. See the [Git\nAlias](#git-alias) section for more details.)_\n\n`git author` has three subcommands. Each subcommand gives you a different view of\nauthorship in your Git repository.\n\n### The `table` Subcommand\n\nThe `table` subcommand is the default subcommand. You can invoke it explicitly\nas `git author table` or implicitly just as `git author`.\n\nThe `table` subcommand prints a table summarizing the contributions of every\nauthor who has made commits in the repository:\n\n```\n~/clones/cpython$ git author\n┌─────────────────────────────────────────────────────┐\n│Author                            Last Edit   Commits│\n├─────────────────────────────────────────────────────┤\n│Guido van Rossum                  2 mon. ago   11,213│\n│Victor Stinner                    1 week ago    7,193│\n│Fred Drake                        13 yr. ago    5,465│\n│Georg Brandl                      1 year ago    5,294│\n│Benjamin Peterson                 4 mon. ago    4,724│\n│Raymond Hettinger                 1 month ago   4,235│\n│Serhiy Storchaka                  3 days ago    3,366│\n│Antoine Pitrou                    10 mon. ago   3,180│\n│Jack Jansen                       18 yr. ago    2,978│\n│Martin v. Löwis                   9 yr. ago     2,690│\n│...3,026 more...                                     │\n└─────────────────────────────────────────────────────┘\n```\n\nYou can specify a path to filter the results to only commits that\ntouched files under the given path:\n\n```\n~/repos/cpython$ git author Tools/\n┌─────────────────────────────────────────────────────┐\n│Author                            Last Edit   Commits│\n├─────────────────────────────────────────────────────┤\n│Guido van Rossum                  8 mon. ago      820│\n│Barry Warsaw                      1 year ago      279│\n│Martin v. Löwis                   9 yr. ago       242│\n│Victor Stinner                    1 month ago     235│\n│Steve Dower                       1 month ago     228│\n│Jeremy Hylton                     19 yr. ago      178│\n│Mark Shannon                      4 hr. ago       131│\n│Serhiy Storchaka                  2 mon. ago      118│\n│Erlend E. Aasland                 1 week ago      117│\n│Christian Heimes                  2 yr. ago       114│\n│...267 more...                                       │\n└─────────────────────────────────────────────────────┘\n```\n\nYou can also specify a branch name, tag name, or any \"commit-ish\" to\nfilter the results to commits reachable from the specified commit:\n\n```\n~/clones/cpython$ git author v3.7.1\n┌─────────────────────────────────────────────────────┐\n│Author                            Last Edit   Commits│\n├─────────────────────────────────────────────────────┤\n│Guido van Rossum                  6 yr. ago    10,986│\n│Fred Drake                        13 yr. ago    5,465│\n│Georg Brandl                      8 yr. ago     5,291│\n│Benjamin Peterson                 6 yr. ago     4,599│\n│Victor Stinner                    6 yr. ago     4,462│\n│Raymond Hettinger                 6 yr. ago     3,667│\n│Antoine Pitrou                    6 yr. ago     3,149│\n│Jack Jansen                       18 yr. ago    2,978│\n│Martin v. Löwis                   9 yr. ago     2,690│\n│Tim Peters                        10 yr. ago    2,489│\n│...550 more...                                       │\n└─────────────────────────────────────────────────────┘\n```\n\nRevision ranges also work. This shows the commits made after the release\nof 3.10.9 up to the release of 3.11.9:\n\n```\n~/clones/cpython$ git author v3.10.9..v3.11.9\n┌─────────────────────────────────────────────────────┐\n│Author                            Last Edit   Commits│\n├─────────────────────────────────────────────────────┤\n│Miss Islington (bot)              9 mon. ago    2,551│\n│Victor Stinner                    9 mon. ago      367│\n│Serhiy Storchaka                  9 mon. ago      304│\n│Erlend Egeberg Aasland            2 yr. ago       202│\n│Christian Heimes                  2 yr. ago       200│\n│Mark Shannon                      1 year ago      157│\n│Irit Katriel                      10 mon. ago     135│\n│Nikita Sobolev                    10 mon. ago     126│\n│Pablo Galindo Salgado             1 year ago      117│\n│Pablo Galindo                     9 mon. ago       97│\n│...574 more...                                       │\n└─────────────────────────────────────────────────────┘\n```\n\nJust like with `git` itself, when there is ambiguity between a path name\nand a commit-ish, you can use `--` to clarify the distinction. The\nfollowing command will show you contributions to the file or directory\ncalled `foo` even if there is also a branch called `foo` in your repository:\n\n```\n$ git author -- foo\n```\n\n#### Options\n\nThe `-m`, `-c`, `-l`, and `-f` flags allow you to sort the table by different\nmetrics.\n\nThe `-m` flag sorts the table by the \"Last Edit\" column, showing who\nedited the repository most recently. The `-c` flag sorts the table by first\nedit, so that the authors who committed to the repository earliest are at the\ntop.\n\nThe `-l` flag sorts the table by number of lines modified, adding some more\ncolumns:\n\n```\n$ git author -l\n┌──────────────────────────────────────────────────────────────────────────────┐\n│Author                          Last Edit   Commits   Files        Lines (+/-)│\n├──────────────────────────────────────────────────────────────────────────────┤\n│Guido van Rossum                2 mon. ago   11,213  14,135     1.3m / 793,252│\n│Antoine Pitrou                  10 mon. ago   3,180   3,868  944,685 / 776,587│\n│Jack Jansen                     18 yr. ago    2,978   5,887  836,527 / 691,078│\n│Benjamin Peterson               4 mon. ago    4,724   6,957  690,740 / 781,700│\n│Georg Brandl                    1 year ago    5,294   9,139  644,620 / 640,217│\n│Martin v. Löwis                 9 yr. ago     2,690   4,557  570,632 / 389,794│\n│Victor Stinner                  1 week ago    7,193  11,382  464,474 / 460,396│\n│Brett Cannon                    1 month ago   2,022   2,841  305,631 / 283,178│\n│Serhiy Storchaka                3 days ago    3,366   9,955  335,209 / 208,899│\n│Christian Heimes                1 year ago    1,553   4,191  339,706 / 178,947│\n│...3,022 more...                                                              │\n└──────────────────────────────────────────────────────────────────────────────┘\n```\n\nThe `-f` flag sorts the table by the number of files modified.\n\nThere is also an `-n` option can be used to print more rows. Passing `-n 0`\nprints all rows.\n\nRun `git-author table --help` to see additional options for the `table` subcommand.\n\n### The `tree` Subcommand\n\nThe `tree` subcommand prints out a file tree showing files in the working tree\njust like [tree](\u003chttps://en.wikipedia.org/wiki/Tree_(command)\u003e). Each node in the\nfile tree is annotated with information showing which author contributed the most\nto files at or under that path.\n\nHere is an example showing contributions to the Python parser. By default,\ncontributions will be measured by number of commits:\n\n```\n~/repos/cpython$ git author tree Parser/\nParser/.........................Guido van Rossum (182)\n├── lexer/......................Pablo Galindo Salgado (5)\n│   ├── buffer.c................Lysandros Nikolaou (1)\n│   ├── buffer.h................Lysandros Nikolaou (1)\n│   ├── lexer.c\n│   ├── lexer.h.................Lysandros Nikolaou (1)\n│   ├── state.c\n│   └── state.h\n├── tokenizer/..................Filipe Laíns (1)\n│   ├── file_tokenizer.c\n│   ├── helpers.c...............Lysandros Nikolaou (1)\n│   ├── helpers.h...............Lysandros Nikolaou (1)\n│   ├── readline_tokenizer.c....Lysandros Nikolaou (1)\n│   ├── string_tokenizer.c......Lysandros Nikolaou (1)\n│   ├── tokenizer.h.............Lysandros Nikolaou (1)\n│   └── utf8_tokenizer.c........Lysandros Nikolaou (1)\n├── Python.asdl.................Benjamin Peterson (14)\n├── action_helpers.c............Pablo Galindo Salgado (6)\n├── asdl.py.....................Benjamin Peterson (7)\n├── asdl_c.py...................Benjamin Peterson (42)\n├── myreadline.c\n├── parser.c....................Pablo Galindo Salgado (34)\n├── peg_api.c...................Lysandros Nikolaou (2)\n├── pegen.c.....................Pablo Galindo (33)\n├── pegen.h.....................Pablo Galindo Salgado (13)\n├── pegen_errors.c..............Pablo Galindo Salgado (16)\n├── string_parser.c.............Victor Stinner (10)\n├── string_parser.h.............Pablo Galindo Salgado (1)\n└── token.c.....................Pablo Galindo Salgado (2)\n```\n\nYou may notice that some files, like `lexer.c`, are not annotated.\nIf a file is not annotated, that is because the author who has\nmost contributed to that file is the same as the author who\nhas most contributed to the directory containing the file. This is\ndone to minimize visual noise.\n\nYou can force `git-author tree` to annotate every file using the `-a`\nflag (for \"all\"). This flag also prints all file paths that\nwere discovered while walking the commit history, including those no\nlonger in the working tree:\n\n```\n~/repos/cpython$ git author tree -a Parser/\nParser/.........................Guido van Rossum (182)\n├── lexer/......................Pablo Galindo Salgado (5)\n│   ├── buffer.c................Lysandros Nikolaou (1)\n│   ├── buffer.h................Lysandros Nikolaou (1)\n│   ├── lexer.c.................Pablo Galindo Salgado (4)\n│   ├── lexer.h.................Lysandros Nikolaou (1)\n│   ├── state.c.................Pablo Galindo Salgado (2)\n│   └── state.h.................Pablo Galindo Salgado (1)\n├── pegen/......................Pablo Galindo (30)\n│   ├── parse.c.................Pablo Galindo (16)\n│   ├── parse_string.c..........Pablo Galindo (7)\n│   ├── parse_string.h..........Pablo Galindo (2)\n│   ├── peg_api.c...............Pablo Galindo (3)\n│   ├── pegen.c.................Pablo Galindo (17)\n│   └── pegen.h.................Pablo Galindo (9)\n├── pgen/.......................Pablo Galindo (8)\n│   ├── __init__.py.............Pablo Galindo (2)\n│   ├── __main__.py.............Pablo Galindo (5)\n│   ├── automata.py.............Pablo Galindo (4)\n│   ├── grammar.py..............Pablo Galindo (5)\n│   ├── keywordgen.py...........Pablo Galindo (3)\n│   ├── metaparser.py...........Pablo Galindo (2)\n│   ├── pgen.py.................Pablo Galindo (5)\n│   └── token.py................Pablo Galindo (4)\n├── tokenizer/..................Filipe Laíns (1)\n│   ├── file_tokenizer.c........Filipe Laíns (1)\n│   ├── helpers.c...............Lysandros Nikolaou (1)\n│   ├── helpers.h...............Lysandros Nikolaou (1)\n│   ├── readline_tokenizer.c....Lysandros Nikolaou (1)\n│   ├── string_tokenizer.c......Lysandros Nikolaou (1)\n│   ├── tokenizer.h.............Lysandros Nikolaou (1)\n│   └── utf8_tokenizer.c........Lysandros Nikolaou (1)\n├── .cvsignore..................Martin v. Löwis (1)\n├── Makefile.in.................Guido van Rossum (10)\n├── Python.asdl.................Benjamin Peterson (14)\n├── acceler.c...................Guido van Rossum (17)\n├── action_helpers.c............Pablo Galindo Salgado (6)\n├── asdl.py.....................Benjamin Peterson (7)\n├── asdl_c.py...................Benjamin Peterson (42)\n├── assert.h....................Guido van Rossum (11)\n├── bitset.c....................Guido van Rossum (12)\n├── firstsets.c.................Guido van Rossum (13)\n├── grammar.c...................Guido van Rossum (20)\n...\n```\n\n(_The above output continues but has been elided for the purposes\nof this README._)\n\nNote that, whether or not the `-a` flag is used, commits that\nedited files not in the working tree will still count toward the total\ndisplayed next to ancestor directories of that file. In the above two examples,\nGuido van Rossum is shown as the overall highest committer to the `Parser/`\ndirectory, though it takes listing the entire tree with the `-a` flag to see\nthat most of his commits were to files that have since been moved or deleted.\n\nLike with the `table` subcommand, you can specify a \"commit-ish\". This\nnext example shows changes to the `Parser/` directory that happened\nafter the 3.10.9 release up to the 3.11.9 release.\n\n```\n~/clones/cpython$ git author tree v3.10.9..v3.11.9 -- Parser/\nParser/.................Pablo Galindo Salgado (52)\n├── Python.asdl.........Batuhan Taskaya (1)\n├── action_helpers.c....Matthieu Dartiailh (1)\n├── asdl_c.py...........Batuhan Taskaya (4)\n├── myreadline.c........Victor Stinner (1)\n├── parser.c\n├── pegen.c\n├── pegen.h\n├── pegen_errors.c......Miss Islington (bot) (8)\n└── string_parser.c.....Miss Islington (bot) (4)\n```\n\nIf a file isn't edited in any of the commits specified by the revision range,\nthen it won't appear in the output of `git author tree`, even if the file is in\nthe working tree. This can make `git author tree` useful for visualizing the\nchanges introduced by a branch.\n\n#### Options\n\nThe `tree` subcommand, like the `table` subcommand, supports the `-l`, `-f`,\n`-m`, and `-c` flags.\n\nThe `-l` flag will annotate each file tree node with the\nauthor who has added or removed the most lines at that path:\n\n```\n~/repos/cpython$ git author tree -l Parser/\nParser/.........................Pablo Galindo (72,917 / 47,102)\n├── lexer/......................Lysandros Nikolaou (1,668 / 0)\n│   ├── buffer.c\n│   ├── buffer.h\n│   ├── lexer.c\n│   ├── lexer.h\n│   ├── state.c\n│   └── state.h.................Pablo Galindo Salgado (1 / 0)\n├── tokenizer/..................Lysandros Nikolaou (1,391 / 0)\n│   ├── file_tokenizer.c\n│   ├── helpers.c\n│   ├── helpers.h\n│   ├── readline_tokenizer.c\n│   ├── string_tokenizer.c\n│   ├── tokenizer.h\n│   └── utf8_tokenizer.c\n├── Python.asdl.................Benjamin Peterson (120 / 122)\n├── action_helpers.c\n├── asdl.py.....................Eli Bendersky (276 / 331)\n├── asdl_c.py...................Victor Stinner (634 / 496)\n├── myreadline.c................Guido van Rossum (365 / 226)\n├── parser.c\n├── peg_api.c...................Victor Stinner (5 / 46)\n├── pegen.c\n├── pegen.h\n├── pegen_errors.c\n├── string_parser.c\n├── string_parser.h\n└── token.c.....................Serhiy Storchaka (233 / 0)\n```\n\nThe `-f` flag will pick authors based on number of files edited. The `-m` flag\nwill pick an author based on last modification time while the `-c` flag picks\nthe author who first edited a file.\n\nYou can limit the depth of the tree printed by using the `-d` flag. The depth\nis measured from the current working directory.\n\nThe `-a` flag has already been mentioned.\n\nRun `git author tree --help` to see all options available for the `tree` subcommand.\n\n### The `hist` Subcommand\n\nThe `hist` subcommand prints out a little bar chart / timeline of commit\nactivity showing the history of contributions to the repository.\n\n```\n~/clones/cpython$ git author hist\n1990 ┤ #                                     Guido van Rossum (105)\n1991 ┤ ##                                    Guido van Rossum (445)\n1992 ┤ ###                                   Guido van Rossum (606)\n1993 ┤ #-                                    Guido van Rossum (200)\n1994 ┤ ###                                   Guido van Rossum (525)\n1995 ┤ ####-                                 Guido van Rossum (869)\n1996 ┤ ####---                               Guido van Rossum (961)\n1997 ┤ #######--                             Guido van Rossum (1,626)\n1998 ┤ #####------                           Guido van Rossum (1,205)\n1999 ┤ ###-----                              Fred Drake (755)\n2000 ┤ ####------------                      Fred Drake (973)\n2001 ┤ #####-----------------                Fred Drake (1,196)\n2002 ┤ ###--------------                     Guido van Rossum (543)\n2003 ┤ ##------------                        Raymond Hettinger (479)\n2004 ┤ ##--------                            Raymond Hettinger (460)\n2005 ┤ #----                                 Raymond Hettinger (171)\n2006 ┤ ###-------------                      Neal Norwitz (636)\n2007 ┤ ####------------                      Guido van Rossum (792)\n2008 ┤ ####--------------------              Georg Brandl (1,005)\n2009 ┤ #####-----------------------          Benjamin Peterson (1,107)\n2010 ┤ #####-------------------------------  Georg Brandl (1,088)\n2011 ┤ ####-----------------                 Victor Stinner (877)\n2012 ┤ ##------------------                  Antoine Pitrou (466)\n2013 ┤ ###--------------                     Victor Stinner (570)\n2014 ┤ ###----------                         Victor Stinner (594)\n2015 ┤ ###---------                          Victor Stinner (529)\n2016 ┤ ##-----------                         Victor Stinner (497)\n2017 ┤ ##--------                            Victor Stinner (404)\n2018 ┤ ##--------                            Victor Stinner (306)\n2019 ┤ ##----------                          Victor Stinner (467)\n2020 ┤ ###---------                          Victor Stinner (524)\n2021 ┤ ##----------                          Victor Stinner (260)\n2022 ┤ ##-------------                       Victor Stinner (366)\n2023 ┤ ###---------------                    Victor Stinner (556)\n2024 ┤ ##-----------------                   Serhiy Storchaka (321)\n2025 ┤ #                                     Bénédikt Tran (27)\n```\n\n(Git was only released in 2005, so clearly there has been some version control\nmetadata imported from another tool!)\n\nThe timeline shows the author who made the most commits in each year. The bar\nin the bar chart shows their contributions as a proportion of the total\ncontributions made in that year. (The `#` symbol shows the proportion\nof total commits by the \"winning\" author for that year.)\n\nLike with the other subcommands, you can filter the commits examined to just\nthose editing files under a given path:\n\n```\n~/repos/cpython$ git author hist iOS/\nFeb 2024 ┤ #                                     Russell Keith-Magee (1)\nMar 2024 ┤ ####                                  Russell Keith-Magee (4)\nApr 2024 ┤ #-                                    Xie Yanbo (1)\nMay 2024 ┤\nJun 2024 ┤\nJul 2024 ┤ #                                     Russell Keith-Magee (1)\nAug 2024 ┤ ##                                    Russell Keith-Magee (2)\nSep 2024 ┤ #                                     Russell Keith-Magee (1)\nOct 2024 ┤\nNov 2024 ┤ #                                     Russell Keith-Magee (1)\nDec 2024 ┤ ###-                                  Russell Keith-Magee (3)\nJan 2025 ┤\n```\n\nThe printed timeline will begin with the date of the first commit modifying\nthat path.\n\nYou can also filter using a commit-ish. This shows the timeline of contributions\nsince Python's 3.12 release.\n\n```\n~/clones/cpython$ git author hist v3.12.0..\nMay 2023 ┤ ###---------                          Victor Stinner (28)\nJun 2023 ┤ #######--------------------           Victor Stinner (90)\nJul 2023 ┤ ######----------------------------    Victor Stinner (78)\nAug 2023 ┤ #######-------------------------      Victor Stinner (91)\nSep 2023 ┤ ############----------------------    Victor Stinner (157)\nOct 2023 ┤ #####---------------------------      Victor Stinner (68)\nNov 2023 ┤ ###---------------------              Serhiy Storchaka (40)\nDec 2023 ┤ ###-----------------------            Alex Waygood (32)\nJan 2024 ┤ ####-----------------------------     Serhiy Storchaka (43)\nFeb 2024 ┤ ####------------------------------    Serhiy Storchaka (42)\nMar 2024 ┤ #####---------------------------      Victor Stinner (59)\nApr 2024 ┤ ###---------------------------        Serhiy Storchaka (37)\nMay 2024 ┤ ##----------------------------------  Serhiy Storchaka (26)\nJun 2024 ┤ ####------------------------          Victor Stinner (48)\nJul 2024 ┤ ###------------------------           Sam Gross (32)\nAug 2024 ┤ ##-------------------                 Mark Shannon (24)\nSep 2024 ┤ ##---------------------------         Serhiy Storchaka (23)\nOct 2024 ┤ ###----------------------------       Victor Stinner (39)\nNov 2024 ┤ ##-----------------------             Serhiy Storchaka (27)\nDec 2024 ┤ ##------------------                  Bénédikt Tran (18)\nJan 2025 ┤ ##---------                           Bénédikt Tran (26)\n```\n\n#### Options\n\nThe `hist` subcommand supports the `-l` and `-f` flags but not the `-m` or `-c`\nflags:\n\n```\n~/repos/cpython$ git author hist -l iOS/\nFeb 2024 ┤ ###############                       Russell Keith-Magee (406 / 0)\nMar 2024 ┤ ####################################  Russell Keith-Magee (994 / 32)\nApr 2024 ┤ #                                     Xie Yanbo (2 / 2)\nMay 2024 ┤\nJun 2024 ┤\nJul 2024 ┤ #                                     Russell Keith-Magee (1 / 1)\nAug 2024 ┤ #                                     Russell Keith-Magee (2 / 0)\nSep 2024 ┤ #                                     Russell Keith-Magee (6 / 0)\nOct 2024 ┤\nNov 2024 ┤ #####                                 Russell Keith-Magee (104 / 28)\nDec 2024 ┤ ##################-                   Russell Keith-Magee (444 / 52)\nJan 2025 ┤\n```\n\nRun `git author hist --help` for a full listing of the options supported by the\n`hist` subcommand.\n\n### Additional Options for Filtering Commits\n\nAll of the `git author` subcommands take these additional options that further\nfilter the commits that get counted.\n\nThe `--author` and `--nauthor` options allow you to specify authors to include\nor exclude. Both options can be specified multiple times to include or exclude\nmultiple authors.\n\nThe `--since` and `--until` options allow you to filter out commits before or\nafter a certain date respectively. These options each take a string that gets\npassed to `git log` to be interpreted. `git log` can handle some surprising\ninputs. See git-commit(1) for a description of what is possible.\n\nThe following example shows the paths edited by Guido van Rossum over the last\neight months:\n\n```\n~/repos/cpython$ git author tree -d 1 --since \"nine months ago\" --author \"Guido van Rossum\"\n./..................Guido van Rossum (11)\n├── .github/........Guido van Rossum (2)\n├── Doc/............Guido van Rossum (3)\n├── Include/........Guido van Rossum (3)\n├── Lib/............Guido van Rossum (1)\n├── Modules/........Guido van Rossum (1)\n├── Objects/........Guido van Rossum (1)\n├── PCbuild/........Guido van Rossum (2)\n├── Programs/.......Guido van Rossum (1)\n├── Python/.........Guido van Rossum (4)\n├── Tools/..........Guido van Rossum (1)\n├── configure\n└── configure.ac\n```\n\n## Caching\n\n`git author` caches data on a per-repository basis under `XDG_CACHE_HOME` (this is\n`~/.cache` if the environment variable is not set).\n\nYou can disable caching by setting `GIT_WHO_DISABLE_CACHE=1`.\n\n## Using `git-author` with Docker\n\nYou can run `git-author` as a Docker container without installing it on your\nsystem directly. Follow these steps to build and use the Docker image.\n\n### Building the Docker Image\n\nTo build the `git-author` Docker image, run the following command from the project root:\n\n```\ndocker build -t git-author -f docker/Dockerfile .\n```\n\nThis will create a Docker image named `git-author` that you can use to run the tool.\n\n### Running `git-author` via Docker\n\nTo use git-author without modifying your Git configuration, you can manually run:\n\n```\ndocker run --rm -it -v \"$(pwd)\":/git -v \"$HOME\":/root git-author author\n```\n\n- `--rm`: Automatically remove the container after execution.\n- `-it`: Enable interactive mode (for a better experience with CLI tools).\n- `-v \"$(pwd):/git\"`: Mounts the current Git repository into the container.\n- `-v \"$HOME:/root\"`: Ensures that user-specific configurations (e.g., SSH keys, Git settings) are available inside the container.\n\n### Setting Up a Git Alias\n\nTo make it easier to run `git-author`, you can add an alias to your Git\nconfiguration. Add the following lines to your `~/.gitconfig` file:\n\n```\n[alias]\n    author = !zsh -c \"docker run --rm -it -v$(pwd):/git -v$HOME:/root git-author author $*\"\n```\n\nThis allows you to run:\n\n```\ngit author\n```\n\nfrom any Git repository, and it will invoke git-author through Docker.\n\n## Git Alias\n\nIf you install the `git-author` binary somewhere in your path, running `git author`\nwill automatically invoke it with no further configuration. This is a Git\nfeature.\n\nIf you install the binary using a different name or just like to be explicit\nyou can configure a Git alias in your global Git config like so:\n\n```\n[alias]\n    author = \"!git-author-executable-name\"\n```\n\nSee [here](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) for more\ninformation about Git aliases.\n\n## Git Mailmap\n\nQuite often, people end up committing to a repository under different names or\nusing different email addresses. For example, someone might make a commit using\nthe name \"Nathan Smith\" and their work email address and then later make a\ncommit using the name \"Nate Smith\" and their personal email address.\n\nHow can you make sure that all of someone's commits are counted together\ninstead of being attributed to three or four different people with slightly\ndifferent names?\n\nGit already has a solution for his problem called [Git\nmailmap](https://git-scm.com/docs/gitmailmap). If a `.mailmap` file is present\nin a Git repository, `git author` will respect it.\n\n## What Exactly Do These Numbers Mean?\n\n### Metrics\n\nThe number of **commits** shown for each author is the number of unique commits\nfound while walking the commit log. When supplying a path argument to `git\nauthor`, the commits walked include only commits modifying the given path(s).\nHere, the rules described under the HISTORY SIMPLIFICATION section of Git log\napply—branches in the commit history that do not modify the given path(s) are\npruned away.\n\nThe number of **files** shown for each author is the number of unique files\nmodified in commits by that author. If a file is renamed, it will count twice.\n\nThe number of **lines added** and **lines removed** shown for each author is\nthe number of lines added and removed to files under the supplied path(s) or to\nall files in the case of no path arguments. In Git, modifying a line counts as\nremoving it and then adding the new version of the line.\n\n### Merge Commits\n\nMerge commits are not counted toward any of these metrics. The rationale here\nis that merge commits represent a kind of overhead involved in managing the\ncommit graph and that all novel changes will already have been introduced to\nthe commit graph by the merge commit's ancestor commits.\n\nYou can supply the `--merges` flag to `git author` to change this behavior. The\n`--merges` flag forces `git author` to count merge commits toward the commit total\nfor each author. Merge commits are still ignored for the purposes of the file\ntotal or lines total.\n\n### Differences From `git blame`\n\nWhereas `git blame` starts from the code that exists in the working tree and\nidentifies the commit that introduced each line, `git author` instead walks some\nsubset of the commit log tallying contributions. This means that `git blame`\nand `git author`, in addition to operating on different levels (individual files\nvs file trees), tell you slightly different things.\n\nThis is best illustrated through an example. If John has made dozens of commits\nediting a file, but Alice recently formatted the file and made one big commit\nwith her style changes, `git blame` will attribute most of the lines in the\nfile to Alice. `git author`, on the other hand, will rank John as the primary\nauthor, at least when sorting by number of commits. In this case, `git author`\nseems better suited to answering the question, \"Who came up with the code in\nthis file?\"\n\nIf instead, John made the same commits but Alice came along later and completely\nrefactored the file, again in one big commit, `git blame` will correctly\nattribute most of the lines in the file to her, while `git author` will still list\nJohn as the primary author. In this case, `git blame` seems to do a better job\nof answering, \"Who came up with the code in this file?\". That said, the various\nsubcommands and options of `git author` can give you the full picture of what has\nhappened here. `git author hist` in particular will show you that John was the\nprimary author until Alice took over.\n\nUltimately, neither tool quite answers what we want to know, which is \"Who came\nup with the code in this file?\", perhaps because the question is too ambiguous.\n`git blame` answers, \"Who last modified each line of code in this file?\" and\n`git author` answers, \"Who made the most modifications to this file / this file\ntree?\"\n\n## DEVELOPMENT\n\n### Test Repository Submodule\n\nSome of the automated tests for `git-author` need to run against a Git repository.\nA test repository is attached to this repository as a submodule.\n\nIf you want to run the automated tests, you will first need to set up the\nsubmodule:\n\n```\n$ git submodule update --init\n```\n\n## 🤝 How to contribute\n\nWe welcome contributions!\n\n- Fork this repository;\n- Create a branch with your feature: `git checkout -b my-feature`;\n- Commit your changes: `git commit -m \"feat: my new feature\"`;\n- Push to your branch: `git push origin my-feature`.\n\nOnce your pull request has been merged, you can delete your branch.\n\n## 📝 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrinhminhtriet%2Fgit-author","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrinhminhtriet%2Fgit-author","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrinhminhtriet%2Fgit-author/lists"}