Who Will Maintain Vim? A Demo of Git Who
Bram Moolenaar, creator and long-time maintainer of the Vim text editor, died
in 2023. His death was a great loss. He left behind a piece of software used
and beloved by many, as well as some big questions: Who will keep Vim going now
that he is gone? Are there other contributors that can take over? Has anyone
been working on Vim since he died?
I recently released an open-source command-line tool called git
who that can answer some of these
questions. I wanted to build the tool because I’ve long been fascinated by what
we can learn about a codebase from the metadata in its commit history. The
commit history embeds a lot of information, especially about the people behind
the codebase. git who
surfaces this information. As a Vim user myself, I’m
curious to see what git who
can tell me about who is working on Vim now. I
also hope this example will show how git who
can be useful.
In the below code blocks, the tool is invoked as git who
, which requires
setting up a Git
alias.
Without the alias, you would invoke it as git-who
.
Who Built Vim?
Bram Moolenaar is known for creating Vim, but did other people help him?
To find out, we can clone the Vim repository and
then run git who
on our local copy:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~/clones/vim$ git who
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│Bram Moolenaar 1 year ago 16,562│
│Christian Brabandt 15 hr. ago 677│
│zeertzjq 2 days ago 570│
│Yegappan Lakshmanan 2 weeks ago 453│
│K.Takata 5 mon. ago 115│
│Doug Kearns 2 days ago 79│
│glepnir 16 hr. ago 78│
│Aliaksei Budavei 16 hr. ago 78│
│LemonBoy 8 mon. ago 76│
│Ernie Rael 1 month ago 75│
│...587 more... │
└—————————————————————————————————————————————————————┘
|
git who
returns a listing of the top contributors to the repository ordered
by the number of commits each has made. There are almost 600 contributors! But
we can also see that Moolenaar has made an order of magnitude more commits
than anyone else.
“Number of commits” is not the only metric we might employ to measure
contributions to a codebase. We can use the -l
flag to list the top
contributors ordered by the number of lines they have added or deleted:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~/clones/vim$ git who -l
┌——————————————————————————————————————————————————————————————————————————————┐
│Author Last Edit Commits Files Lines (+/-)│
├——————————————————————————————————————————————————————————————————————————————┤
│Bram Moolenaar 1 year ago 16,562 4,869 3.5m / 1.7m│
│Yegappan Lakshmanan 2 weeks ago 453 456 106,672 / 54,979│
│Christian Brabandt 16 hr. ago 677 890 51,685 / 30,657│
│Luca Saccarola 1 week ago 35 64 18,231 / 17,788│
│Doug Kearns 2 days ago 79 921 25,298 / 9,533│
│JNylson 6 mon. ago 4 2 17,151 / 17,124│
│RestorerZ 17 hr. ago 43 240 15,140 / 15,547│
│zeertzjq 2 days ago 570 593 21,296 / 7,541│
│Aliaksei Budavei 16 hr. ago 78 708 18,009 / 6,215│
│Restorer 10 mon. ago 28 45 15,165 / 7,457│
│...585 more... │
└——————————————————————————————————————————————————————————————————————————————┘
|
Some new columns have appeared. In the last column, we can see that Moolenaar
has also contributed an order of magnitude more lines of code to Vim than any
other contributor.
So far we have been implicitly using the table
subcommand of git who
. (We could have written that last command as git who table -l
.) We can
use another subcommand, hist
, to get a sense of how the top contributor has
changed over time:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
~/clones/vim$ git who hist
2004 ┤ # Bram Moolenaar (46)
2005 ┤ ######### Bram Moolenaar (578)
2006 ┤ ####### Bram Moolenaar (428)
2007 ┤ ###### Bram Moolenaar (392)
2008 ┤ ##### Bram Moolenaar (318)
2009 ┤ #### Bram Moolenaar (249)
2010 ┤ ########## Bram Moolenaar (636)
2011 ┤ ##### Bram Moolenaar (317)
2012 ┤ ####### Bram Moolenaar (400)
2013 ┤ ############ Bram Moolenaar (797)
2014 ┤ ######## Bram Moolenaar (466)
2015 ┤ ######## Bram Moolenaar (493)
2016 ┤ ######################## Bram Moolenaar (1,574)
2017 ┤ ##################### Bram Moolenaar (1,335)
2018 ┤ ################## Bram Moolenaar (1,135)
2019 ┤ ############################# Bram Moolenaar (1,875)
2020 ┤ ################################## Bram Moolenaar (2,236)
2021 ┤ #####################------ Bram Moolenaar (1,395)
2022 ┤ #########################----------- Bram Moolenaar (1,636)
2023 ┤ ####------------------ Bram Moolenaar (256)
2024 ┤ ######---------------------- Christian Brabandt (363)
2025 ┤ ##---- Christian Brabandt (67)
|
git who
gives us a lot of information here. For each year, we are shown who
made the most commits in that year and how many commits that person made. The
bar graph gives us a sense of how the number of commits varies from year to
year. In some years, the top contributor only contributes a fraction of the
total number of commits made that year; you can see that in 2023, for example,
Moolenaar’s commits (represented by #
) do not fill the entire bar. The
remaining portion of the bar (represented by -
) accounts for commits made by
contributors not named “Bram Moolenaar.”
In most of the above years, Moolenaar appears to have been the only contributor
to Vim. It was only after 2023 that Christian Brabandt became the top
contributor. From what I can understand, Brabandt has inherited
leadership of the Vim
project. It is
interesting to see this succession borne out in the commit history.
Still, it is clear that Vim was a solo project for most of its existence. And
this timeline only goes back to the beginning of Vim’s Git commit history. Vim
was initially released in 1991, well before Linus Torvalds created Git. Other
people might have contributed to Vim before it was put under Git version
control. But from what we can see in the Git history, Moolenaar left large
shoes to fill.
We can confirm that other contributors began committing to the Vim repo only
recently using the --nauthor
flag (for “not author”) to exclude Moolenaar
from the timeline:
1
2
3
4
5
6
7
8
|
~/clones/vim$ git who hist --nauthor "Bram Moolenaar"
2019 ┤ # Christian Brabandt (1)
2020 ┤ # Jay Sitter (1)
2021 ┤ ##----- Yegappan Lakshmanan (87)
2022 ┤ ###------------ zeertzjq (148)
2023 ┤ ####------------------- Christian Brabandt (193)
2024 ┤ ########---------------------------- Christian Brabandt (363)
2025 ┤ ##------ Christian Brabandt (67)
|
The timeline now begins only in 2019, when Brabandt made the first
non-Moolenaar commit. Surprisingly, before 2023, Brabandt was not
the top contributor even among people not named “Bram Moolenaar.” (Though keep
in mind that “number of commits” is only one possible metric we could choose,
and further that no metric can capture how much someone has contributed to a
project in a holistic sense.)
Who Is Working On Vim Now?
Moolenaar died on August 3rd, 2023. We can see who has contributed since then
using the --since
flag:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~/clones/vim$ git who --since "August 3rd, 2023"
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│Christian Brabandt 1 day ago 610│
│zeertzjq 2 days ago 334│
│Yegappan Lakshmanan 2 weeks ago 214│
│glepnir 1 day ago 78│
│Aliaksei Budavei 1 day ago 78│
│Doug Kearns 2 days ago 76│
│Wu, Zhenyu 1 month ago 70│
│dkearns 9 mon. ago 67│
│Ken Takata 2 mon. ago 64│
│Ernie Rael 1 month ago 63│
│...427 more... │
└—————————————————————————————————————————————————————┘
|
I am reassured by the large number of contributors I see here. Moolenaar may
have been more or less synonymous with Vim, but it looks like there are many
people who have stepped up to make significant contributions in his absence.
We could also look at the contributors to the v9.1 release, the most recent
version of Vim (as of this writing) and also the first release after
Moolenaar’s passing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~/clones/vim$ git who v9.0.0000..v9.1.0
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│Bram Moolenaar 1 year ago 1,062│
│zeertzjq 1 year ago 234│
│Christian Brabandt 1 year ago 203│
│Yegappan Lakshmanan 1 year ago 177│
│K.Takata 1 year ago 56│
│Philip H 1 year ago 45│
│Luuk van Baal 1 year ago 44│
│Yee Cheng Chin 1 year ago 43│
│Ernie Rael 1 year ago 42│
│Amaan Qureshi 1 year ago 31│
│...253 more... │
└—————————————————————————————————————————————————————┘
|
We can see here that the minor-number release, while an accomplishment, still
included much work by Moolenaar. The real test will be the v9.2 release.
Who are Christian Brabandt, zeertzjq, and Yegappan Lakshmanan? These three seem
to be the main contributors maintaining Vim now. We aren’t going to do any
investigation into their personal or professional lives, but we certainly can
look at who they are within the Vim codebase.
Who Is Contributing What?
git who
has a third subcommand that we’ve not seen yet, called tree
. The
tree
subcommand prints out the files in the Git working tree, along with an
annotation for each file showing the one author that has contributed the “most”
to that file according to a chosen metric.
One simple invocation of git who tree
can show us who has edited each file
most recently. This should yield the same information as can be viewed on Github
when you browse a repository. We use the -m
flag to pick the author who last
modified each file. The -d
flag limits the depth of the tree.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
~/clones/vim$ git who tree -d 1 -m
./............................Christian Brabandt (1 day ago)
├── .github/..................Jonathan (1 day ago)
├── READMEdir/................Nir Lichtman (5 mon. ago)
├── ci/.......................Christ van Willegen (3 weeks ago)
├── lang/.....................Rafael Fontenelle (2 weeks ago)
├── nsis/.....................Rafael Fontenelle (2 weeks ago)
├── pixmaps/..................Bram Moolenaar (3 yr. ago)
├── runtime/..................Christian Brabandt (1 day ago)
├── src/......................Christian Brabandt (1 day ago)
├── tools/....................RestorerZ (1 month ago)
├── .appveyor.yml.............RestorerZ (1 year ago)
├── .cirrus.yml...............Philip H. (3 mon. ago)
├── .clang-format.............Luca Saccarola (3 mon. ago)
├── .codecov.yml..............dundargoc (1 year ago)
├── .editorconfig.............Maxim Kim (1 week ago)
├── .git-blame-ignore-revs
├── .gitattributes............Bram Moolenaar (5 yr. ago)
├── .gitignore................Eisuke Kawashima (1 week ago)
├── .hgignore.................Eisuke Kawashima (1 week ago)
├── CONTRIBUTING.md...........RestorerZ (1 month ago)
├── Filelist..................RestorerZ (1 day ago)
├── LICENSE
├── Makefile..................Aliaksei Budavei (1 day ago)
├── README.md.................Patrick Brinich-Langlois (9 mon. ago)
├── README.txt................Patrick Brinich-Langlois (9 mon. ago)
├── README_VIM9.md............Bram Moolenaar (2 yr. ago)
├── SECURITY.md
├── configure.................Bram Moolenaar (5 yr. ago)
├── uninstall.txt.............Martin Tournoij (2 yr. ago)
├── vimtutor.bat..............RestorerZ (3 mon. ago)
└── vimtutor.com..............Bram Moolenaar (9 yr. ago)
|
We can see what our trio of top contributors have been working on since the
v9.1 release using a more complicated invocation. Here we filter to particular
authors using the --author
flag and leave out the -m
flag to go back to
ranking authors by number of commits (the default):
1
2
3
4
5
6
7
8
9
10
11
12
|
~/clones/vim$ git who tree --author "zeertzjq" --author "Christian Brabandt" --author "Yegappan Lakshmanan" -d 1 v9.1.0..
./............................Christian Brabandt (424)
├── .github/..................Christian Brabandt (10)
├── READMEdir/................zeertzjq (1)
├── nsis/.....................Christian Brabandt (2)
├── runtime/..................Christian Brabandt (241)
├── src/......................zeertzjq (219)
├── .git-blame-ignore-revs
├── CONTRIBUTING.md
├── Filelist
├── Makefile
└── README.md
|
An interesting observation we can make here is that Brabandt seems to have
specialized in maintaining Vim’s runtime files (mostly VimScript code), while
zeertzjq seems to have specialized in maintaining the editor core (written in
C).
Also note that our tree has been truncated and most of the files that appeared
in it above no longer appear. This is because git who tree
only includes
files in the tree that were edited by a commit in the provided revision range.
In this case we limited the command to commits occurring after the v9.1
release.
The output of git who tree
, since it only shows a single “winner” for each
file node, can be misleading. We can sanity check our conclusion about what
Brabandt and zeertzjq are working on using the table
subcommand on the src
directory:
1
2
3
4
5
6
7
8
|
~/clones/vim$ git who --author "zeertzjq" --author "Christian Brabandt" --author "Yegappan Lakshmanan" v9.1.0.. src/
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│zeertzjq 3 days ago 219│
│Christian Brabandt 1 day ago 206│
│Yegappan Lakshmanan 2 weeks ago 106│
└—————————————————————————————————————————————————————┘
|
This reveals that while zeertzjq has made more commits affecting files under
the src
directory than Brabandt, Brabandt has not been far behind. So maybe a
better conclusion is that both Brabandt and zeertzjq are committing to the
editor core, but Brabandt seems to be taking the lead on maintaining the
runtime files:
1
2
3
4
5
6
7
8
|
~/clones/vim$ git who --author "zeertzjq" --author "Christian Brabandt" --author "Yegappan Lakshmanan" v9.1.0.. runtime/
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│Christian Brabandt 1 day ago 241│
│zeertzjq 3 days ago 73│
│Yegappan Lakshmanan 4 weeks ago 35│
└—————————————————————————————————————————————————————┘
|
What of Lakshmanan? We can filter just for him to make sure his contributions
appear:
1
2
3
4
5
|
~/clones/vim$ git who tree --author "Yegappan Lakshmanan" -d 1 v9.1.0..
./..............Yegappan Lakshmanan (114)
├── runtime/....Yegappan Lakshmanan (35)
├── src/........Yegappan Lakshmanan (106)
└── Filelist
|
He has contributed to both the runtime
and src
directories, but has made
fewer commits than his peers and so his name did not appear earlier.
We can dive deeper and get a sense for all of the changes Lakshmanan has made
since the v9.1 release. In this next invocation, we are increasing the depth of
the tree, showing lines changed/added rather than number of commits, and
finally passing the -a
flag to force git who
to annotate every file. (git who
will by default remove some redundant annotations to reduce visual noise.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
~/clones/vim$ git who tree -l -a -d 2 --author "Yegappan Lakshmanan" v9.1.0..
./...........................Yegappan Lakshmanan (22,033 / 8,176)
├── runtime/.................Yegappan Lakshmanan (2,836 / 404)
│ ├── autoload/............Yegappan Lakshmanan (219 / 0)
│ ├── doc/.................Yegappan Lakshmanan (977 / 232)
│ ├── ftplugin/............Yegappan Lakshmanan (45 / 0)
│ ├── pack/................Yegappan Lakshmanan (183 / 169)
│ ├── plugin/..............Yegappan Lakshmanan (6 / 0)
│ ├── syntax/..............Yegappan Lakshmanan (93 / 0)
│ ├── tutor/...............Yegappan Lakshmanan (1,307 / 0)
│ ├── defaults.vim.........Yegappan Lakshmanan (3 / 3)
│ └── filetype.vim.........Yegappan Lakshmanan (3 / 0)
├── src/.....................Yegappan Lakshmanan (19,191 / 7,772)
│ ├── proto/...............Yegappan Lakshmanan (49 / 25)
│ ├── testdir/.............Yegappan Lakshmanan (8,936 / 2,292)
│ ├── Make_ami.mak.........Yegappan Lakshmanan (1 / 0)
│ ├── Make_cyg_ming.mak....Yegappan Lakshmanan (1 / 0)
│ ├── Make_mvc.mak.........Yegappan Lakshmanan (4 / 0)
│ ├── Make_vms.mms.........Yegappan Lakshmanan (6 / 0)
│ ├── Makefile.............Yegappan Lakshmanan (17 / 2)
│ ├── README.md............Yegappan Lakshmanan (1 / 0)
│ ├── buffer.c.............Yegappan Lakshmanan (3 / 1)
│ ├── charset.c............Yegappan Lakshmanan (11 / 0)
│ ├── cmdexpand.c..........Yegappan Lakshmanan (27 / 18)
│ ├── dict.c...............Yegappan Lakshmanan (27 / 0)
│ ├── diff.c...............Yegappan Lakshmanan (284 / 37)
│ ├── digraph.c............Yegappan Lakshmanan (2 / 5)
│ ├── errors.h.............Yegappan Lakshmanan (60 / 14)
│ ├── eval.c...............Yegappan Lakshmanan (2,240 / 2,339)
│ ├── evalbuffer.c.........Yegappan Lakshmanan (2 / 0)
│ ├── evalfunc.c...........Yegappan Lakshmanan (526 / 43)
│ ├── evalvars.c...........Yegappan Lakshmanan (80 / 18)
│ ├── ex_cmds.h............Yegappan Lakshmanan (5 / 5)
│ ├── ex_docmd.c...........Yegappan Lakshmanan (310 / 80)
│ ├── ex_getln.c...........Yegappan Lakshmanan (7 / 7)
│ ├── fileio.c.............Yegappan Lakshmanan (1 / 1)
│ ├── filepath.c...........Yegappan Lakshmanan (29 / 27)
│ ├── gc.c.................Yegappan Lakshmanan (783 / 0)
│ ├── globals.h............Yegappan Lakshmanan (9 / 1)
│ ├── if_cscope.c..........Yegappan Lakshmanan (2 / 2)
│ ├── list.c...............Yegappan Lakshmanan (24 / 0)
│ ├── mbyte.c..............Yegappan Lakshmanan (12 / 1)
│ ├── misc1.c..............Yegappan Lakshmanan (11 / 11)
│ ├── option.c.............Yegappan Lakshmanan (87 / 22)
│ ├── option.h.............Yegappan Lakshmanan (6 / 2)
│ ├── optiondefs.h.........Yegappan Lakshmanan (15 / 4)
│ ├── optionstr.c..........Yegappan Lakshmanan (14 / 9)
│ ├── proto.h..............Yegappan Lakshmanan (1 / 0)
│ ├── scriptfile.c.........Yegappan Lakshmanan (12 / 5)
│ ├── strings.c............Yegappan Lakshmanan (290 / 57)
│ ├── structs.h............Yegappan Lakshmanan (28 / 6)
│ ├── terminal.c...........Yegappan Lakshmanan (9 / 2)
│ ├── testing.c............Yegappan Lakshmanan (11 / 2)
│ ├── typval.c.............Yegappan Lakshmanan (25 / 3)
│ ├── undo.c...............Yegappan Lakshmanan (1 / 1)
│ ├── usercmd.c............Yegappan Lakshmanan (2 / 2)
│ ├── userfunc.c...........Yegappan Lakshmanan (212 / 95)
│ ├── version.c............Yegappan Lakshmanan (215 / 1)
│ ├── vim.h................Yegappan Lakshmanan (8 / 4)
│ ├── vim9.h...............Yegappan Lakshmanan (11 / 1)
│ ├── vim9class.c..........Yegappan Lakshmanan (1,009 / 196)
│ ├── vim9cmds.c...........Yegappan Lakshmanan (11 / 5)
│ ├── vim9compile.c........Yegappan Lakshmanan (2,548 / 1,750)
│ ├── vim9execute.c........Yegappan Lakshmanan (269 / 66)
│ ├── vim9expr.c...........Yegappan Lakshmanan (96 / 41)
│ ├── vim9instr.c..........Yegappan Lakshmanan (27 / 5)
│ ├── vim9script.c.........Yegappan Lakshmanan (17 / 8)
│ ├── vim9type.c...........Yegappan Lakshmanan (796 / 555)
│ └── viminfo.c............Yegappan Lakshmanan (1 / 1)
└── Filelist.................Yegappan Lakshmanan (6 / 0)
|
With this increased granularity, we can see that Lakshmanan seems to have made
some big contributions to vim tutor (the tutorial program) and also to eval.c
and vim9compile.c
, two important-sounding files! Lakshmanan also
contributed many lines of code under the src/testdir
directory, but it’s hard
to know without further exploration if those were substantive changes or
something like a bulk change to a test fixture.
To Vim or Neovim
In recent years, a competitor to Vim called Neovim has emerged. Part of the
reason Neovim forked from Vim in the first place was that the organization of
the Vim project made it hard for new contributors to get involved. Fans of
Neovim argue that Neovim has a healthier ecosystem of contributors and plugin
authors than the original Vim and that therefore Neovim will be the version of
Vim with more features and better maintenance going forward.
As we have seen, Vim has many active contributors and has opened up to a wider
group in the last couple years. Work is continuing on the project led by what
appears to be a core group of three contributors. Speaking for myself, I trust
these contributors to keep Vim going strong, though it will be interesting to
see how the v9.2 release (the first one without any contributions from
Moolenaar) will come together.
All that said, are Neovim fans right when they say that Neovim has more support
from the open-source community? I meant to leave this as an exercise for the
reader, but my curiosity has gotten the best of me.
We can very easily see how Neovim compares using git who
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
~/clones/neovim$ git who
┌—————————————————————————————————————————————————————┐
│Author Last Edit Commits│
├—————————————————————————————————————————————————————┤
│zeertzjq 13 hr. ago 4,175│
│Justin M. Keyes 10 hr. ago 2,411│
│Jan Edmund Lazo 3 yr. ago 2,258│
│ZyX 5 yr. ago 1,421│
│Christian Clason 1 day ago 1,318│
│bfredl 1 week ago 1,167│
│dundargoc 2 weeks ago 1,126│
│James McCoy 2 weeks ago 838│
│Thiago de Arruda 8 yr. ago 742│
│Lewis Russell 1 week ago 615│
│...1,211 more... │
└—————————————————————————————————————————————————————┘
|
Immediately we can see that there are many more total contributors to Neovim,
and also that there seems to be a wider group of people who have made
significant contributions. There’s also a spicy finding here—it appears
zeertzjq
is the top contributor to Neovim! One wonders if most of his
contributions to base Vim are in support of Neovim somehow… which would mean
that, at least if we’re trying to evaluate how much momentum the project has on
its own, Vim arguably has just two main contributors and not three.
The output of git who hist
for the Neovim repository is also revealing. But
that one I do leave as an exercise to the reader. Download git
who and give it a spin!
Correction
Reddit user y-c-c pointed out to me that the above analysis of Vim’s commit
history is misleading because for many years Moolenaar gave credit to
contributors in the commit message of patches he committed. So, during the
many years where it looks like Moolenaar was the sole contributor, there were
in fact other people contributing to Vim—it’s just that all of their changes
were introduced to the repo via a commit from Moolenaar.
Typically, a situation like this would be handled in Git by setting the commit
author to the person who wrote the patch and the commit committer to the
person actually making the commit. git who
uses the author field. Still,
everybody is entitled to use their tools their own way; it’s also possible
this convention didn’t exist when Moolenaar first migrated Vim to Git. The
fault is my own for not spot checking the commit history to see how the Vim
project did things. Vim has had more external contributors (and has had them
for far longer) than I represent above.
I think this blog post still serves as an accurate demonstration of git who
—of both its power and major weaknesses! Let this be a warning to anybody
that would use git who
too credulously. Please don’t use it to do something
silly like evaluate your employees.