Git Archaeology
Photo by Sigmund / Unsplash
Or, How We Ended Up With 50 Years of Borrowed Words
I went down this rabbit hole the other night at 2am trying to google and find out what people have been naming their default branches in git besides main and master.
Turns out the answer involves punch cards, Bell Labs, a petty licensing dispute, and the fact that basically every word you use in git was stolen from something older and means something slightly different now.
So heres the whole thing.
The family tree of version control
Before there was version control there was literally a box of punch cards. Your "version" was a physical stack of cards in a box with a label on it. You versioned your code by organizing cardboard. This was the 1960s.
Then things got interesting.
SCCS - the actual OG (1972)
SCCS (Source Code Control System) was built at Bell Labs by Marc Rochkind. This is where it all starts. One file at a time, one user at a time. You want to edit a file? You lock it. Nobody else touches it until youre done. Pessimistic locking they called it, which honestly sounds like my approach to most things.
SCCS gave us check-in and check-out, which is the great grandparent of git commit and git checkout. It also gave us deltas (storing the differences between versions) and revision numbers like 1.1, 1.2 etc.
Ken Thompson had a famous quote about SCCS: "SCCS, the source motel! Programs check in and never check out!" which is honestly still how some repos feel.
RCS - reverse it (1982)
RCS (Revision Control System) came from Walter Tichy at Purdue. Still single file, still local only. But the clever bit was reverse deltas, store the newest version in full and calculate backwards to get older ones. This meant getting the latest version was instant instead of having to rebuild from scratch every time.
RCS used ci and co commands for check-in and check-out. The ci command was apparently very easy to typo as vi which caused all sorts of pain for people. Good times.
CVS - now we're talking (1986)
CVS (Concurrent Versions System) was built by Dick Grune because he needed to collaborate with his students on a compiler project. It was basically a bunch of shell scripts wrapping RCS at first, but the big deal was optimistic locking. Multiple people could edit the same file at the same time and merge later.
This is where a LOT of git terminology was born. commit, checkout, HEAD, branch, merge, repository, update, and log all come from CVS or trace their lineage through it.
SVN - CVS but not broken (2000)
Subversion was explicitly built as "CVS done right." It fixed data corruption issues, supported binary files properly and introduced atomic commits (all your changes go in together or not at all).
SVN formalized the trunk/branches/tags directory convention. This is where the tree metaphor actually made sense. The trunk is the main growth, branches split off from it, tags are snapshots. Its a perfect metaphor. And then git came along and kept the word "branch" but not "trunk" and here we are.
BitKeeper - the catalyst (2000)
BitKeeper was built by Larry McVoy and it was the first widely used distributed VCS. The Linux kernel used it from 2002 to 2005. BitKeeper had master/slave repositories, which is where git's master branch name came from. BitKeeper also had pull and push which git inherited directly.
Then BitKeeper revoked Linux's free license in 2005 and Linus Torvalds got mad enough to write his own version control system in like two weeks.
Git - spite-driven development (2005)
Linus's design goals for git were explicitly stated as: "Take the Concurrent Versions System (CVS) as an example of what not to do; if in doubt, make the exact opposite decision."
So he made the opposite of CVS. Except he kept half the vocabulary. Classic.
Mercurial was announced literally days after git, also in response to the BitKeeper situation. It used default as its branch name. It was simpler than git. It lost anyway.
Every inherited term in git and what it actually used to mean
This is the part thats actually kind of wild. Almost every word in your daily git workflow is a hand-me-down from an older system, and most of them mean something different now than they used to.
checkout - In CVS and SVN this meant "give me a copy of the code from the server." The equivalent in git is git clone. But git reused the word checkout to mean "switch branches" AND "restore files" which are two completely different things. Git eventually admitted this was confusing and added git switch and git restore in 2019. Only took 14 years.
commit - In CVS, committing sent your changes to the central server. In git, committing is purely local. The equivalent of cvs commit is actually git push
This still trips people up constantly.
HEAD - From CVS where it meant the latest revision on the main branch. In git its a pointer to your current branch or commit. Similar idea, totally different mechanics.
master - From BitKeeper's master/slave repository model. Bastien Nocera traced this back through the git source, through BitKeeper's documentation, which explicitly uses master/slave terminology for its repositories. In BitKeeper, repositories and branches are conceptually the same thing. So yes the git master branch traces back to the slavery concept, even if git itself never had a "slave" anything. In 2020 GitHub, GitLab and Bitbucket all switched to main as default.
origin - This ones actually git-native, just convention. When you git clone something, git names the remote origin automatically. Its not special or magic. You could rename it to cheese and everything would still work.
branch - From the SVN tree metaphor where branches were literally directories inside a /branches folder. Git made them lightweight pointers instead of actual directory copies, but kept the name.
tag - Also from SVN's /tags directory convention. In SVN tags were mechanically identical to branches (just directory copies). Git made them actual first-class objects.
merge - From CVS. Same concept, wildly better implementation. CVS merges were famously painful and "merge failure" was apparently a phrase that made developers physically flinch.
diff - Predates all version control entirely. The Unix diff command is from 1974, also from Bell Labs. SCCS used it, RCS used it, everything still uses it.
patch - Also from Unix tooling, predates VCS.
blame - CVS had annotate, SVN had both blame and annotate. Git kept blame because its funnier and honestly more accurate.
revert - This one is actively evil. In SVN, revert undoes your local changes. In git, revert creates a NEW commit that undoes an OLD commit. Completely different operation, same word. Maximum confusion.
update - Another trap. In SVN, update pulls changes from the server (like git pull). In git, seeing "needs update" in an error message actually means you have local changes you need to commit or stash. Not the same thing at all.
.gitignore - Descended from CVS's .cvsignore. Same concept, same convention of a dotfile in the repo root.
clone - This is actually a new concept from distributed VCS. CVS and SVN had checkout for getting a copy, but clone means getting the ENTIRE history which only makes sense in a distributed system.
fetch/pull/push - Git-native concepts born from the distributed model. pull is conceptually descended from BitKeeper's bk pull.
stash - Git-native. No real predecessor.
The missed opportunity
The SVN tree metaphor was perfect. Trunk is the main line. Branches come off the trunk. Tags are like, I dont know, carving your initials in the bark or something.
Then git came along and kept "branches" but called the main line "master" instead of "trunk." So now we have branches coming off of... a master? A main? Thats not how trees work. After trunk, branch, and tags they shoulda gone with leaves or twigs for the small stuff. git leaf -m "photosynthesis complete" would have been beautiful.
Trunk honestly sounds best. Some Google-adjacent teams and trunk-based development people still use it. They're right. The rest of us are living in a world where every word means something different than it used to, half the commands are named after things from systems that no longer exist and we just collectively pretend thats fine.
Which it is. Its fine. Everything is fine.
References and further reading:
Tailscale Changed How I Think About Networking
Newer →If you have nothing to hide