Open a file you wrote last week and you are looking at a present. The words on the screen are the words that are there now. Yesterday's words are gone unless you saved a copy under another name, and last Tuesday's words are gone unless you saved that too. Two people editing the same file produce, without a system, a last-writer-wins present: whoever saved second erased the other. Version control is the system that refuses this. It produces a reconstructable past of the artifact — every recorded state, who made it, when, and usually why — and a protocol for combining two presents that grew from the same past. That pair is the product. Everything else in this essay is a mechanism for manufacturing it, making it cheaper, or recovering it when the combination fails.
We'll build the product from one file on one machine, add a second person, then a tree of files on a central desk — Subversion and Perforce as two living answers — then two distributed ledgers invented in the same month, Mercurial and Git, and finally the public desks where most combining now happens. Three tools will keep coming back: the ledger, an append-only record you never erase; the letter, a description of difference you can store or send; and the braid, two lines of work that fork and must rejoin. The braid has four software names still in use: a directory copy, a stream, a named field inside a commit, a sliding pointer. The figures are interactive. Drag them as we go. Most of them are built so you can find the point before the sentence that names it.
In this essay a line is a line of text, the native grain of these systems. Sizes are in bytes and in lines. Time is in seconds, days, and calendar years. A revision is one recorded state of a file or of a whole tree.
Part 1One file, many pasts
Before there can be a shared history there has to be a history of one thing. The first version-control systems did not know about projects, trees, or networks. They knew about a file, and about the problem of not drowning in copies of it.
The cost of copies
Suppose you have a source file of 2,000 lines, about 80 kilobytes of C, and you change it every working day. If you keep a full copy of each day's file, 200 working days leave you 16 megabytes of near-duplicates — 200 × 80 kB — and the 201st copy does not tell you what changed. The information you actually want is the difference: usually a few dozen lines. If a typical day's edit rewrites 2 percent of the file, the 200 differences occupy about 200 × 1.6 kB = 320 kB, plus one full copy of 80 kB, or 400 kB against 16 MB. The ledger of change is forty times smaller than the shelf of copies, and unlike the shelf it is a ledger: a sequence of transactions, not a pile of photographs.
That arithmetic is why these systems exist as delta machines rather than as backup tools. A delta is a recipe: insert these lines, delete those. Apply the recipe to yesterday's file and you get today's. Apply it backwards and you get yesterday from today. The letter you would mail to a colleague is the same object as the record you would store.
The idea is older than Unix. Programmers on IBM mainframes in the 1960s already kept card decks and used update utilities to apply a change deck to a master. A 2,000-line program on punched cards is 2,000 cards, one statement each; ten saved versions is a stack you can trip over. Marc Rochkind, twenty-five years old at Bell Labs in 1972, was asked to do something about "source code chaos" in a group writing mainframe programs for telephone companies. He did not know about those earlier tools. Walking a dog one evening in Sayreville, New Jersey, he invented an encoding that would store every version of a file in one place and retrieve any version in a single pass over that place.
Play with the figure until the ratio sits still in your head. At 2 percent edits and 200 versions the copies occupy 16 MB and the deltas occupy 400 kB; at 10 percent edits the advantage shrinks but does not vanish. History is cheap when you store the letters instead of the books.
A single pass
Rochkind's encoding is called a weave, or an interleaved delta. Imagine the file as a stack of lines, but each line is tagged with the version that inserted it and, if it was later deleted, the version that deleted it. The stored file is not version 17 or version 3. It is every line that ever lived, in the order they appear, wearing those tags. To reconstruct version 7 you read the weave once, from top to bottom, and keep a line if it had been inserted by version 7 or earlier and had not yet been deleted by version 7. One sequential pass. The version you want does not change how much you read.
That is a different design from "store version 1 in full, then a delta to 2, then a delta to 3." In a chain of forward deltas, version 100 is 99 applications away. In a weave, version 100 and version 1 cost the same read. Rochkind proved the reconstruction correct by enumerating the mixed cases of insertion and deletion, implemented it in SNOBOL4 on an IBM System/370 running OS/360, and had it working in days. He rewrote it in C for Unix in 1973. The system was named the Source Code Control System, SCCS. The first paper appeared in IEEE Transactions on Software Engineering in December 1975. A text-format version shipped with the Programmer's Workbench Unix on February 18, 1977.
The figure is the algorithm. You did not apply nine deltas. You asked, of each line, whether it was alive at the version you named.
The latest is the whole
SCCS made every version equally cheap to reconstruct. Most programmers, most of the time, want the latest one. Walter Tichy, at Purdue, built the Revision Control System around that observation and published it in 1982, with a fuller account in Software: Practice and Experience in 1985. RCS stores the newest revision as a complete file, and stores older revisions as reverse deltas — recipes that turn a later file into an earlier one. Checking out the tip is a copy. Checking out version 1 of a file with 200 revisions means applying 199 reverse deltas. The common case is a read; the archaeological case is a chain.
Tichy's paper compared the encodings with usage statistics from real trees. Reverse deltas win when the tip is the usual request, which it is: compile this, test this, edit this. They lose when you replay history, which SCCS's weave does not. The two systems are answers to different questions about the same ledger. SCCS is a volume you can slice at any year for the same price. RCS is a photograph of today plus a stack of letters that describe how to get back.
Unix diff, which produces those letters, is itself a research object. James Hunt and Douglas McIlroy published the original algorithm as Bell Labs Computing Science Technical Report 41 in 1976, after a diff had already shipped in Fifth Edition Unix in 1974. Eugene Myers published an O(ND) algorithm in 1986 — N the sum of the lengths, D the size of the shortest edit script — and GNU diff uses a Myers variant. The letter is a shortest path through an edit graph whose horizontal edges are deletions, vertical edges insertions, and diagonals matches.
The lock on the cabinet
A ledger with one writer is a diary. A ledger with two writers is an accounting problem. SCCS and RCS both solved the problem by locking. To edit a file you checked it out with a lock; the system wrote your name on the cabinet; everyone else could read but not write until you checked in. The lock is a physical leftover as much as a protocol: if you go home on Friday with the lock, the cabinet stays closed until Monday, or until an administrator breaks it.
Let's put numbers on contention. Eight people share a module of twelve files. Each person holds a lock on one file for thirty minutes a day. That is four person-hours of lock per eight-hour day, on a cabinet that can grant only one writer per file. If two people need the same file on the same afternoon, one waits. The wait is not a failure of manners. It is the mechanism working as designed: the product — a linear history of that file — is preserved by forbidding the braid.
A name inside the text
SCCS embedded a string in the source, the sccsid, which the tools would update on every delta: a version number, a date, a time, who. A compiled program could still be asked what and would print the embedded strings, so a binary in the field could name the exact sources it was built from. RCS did the same with $Id$ keywords. The ledger leaked a little of itself into the artifact, on purpose, because the product is not only reconstructable on the machine that holds the history file. It is identifiable wherever a copy of the program has traveled.
The letter itself has a size, and that size is the other half of Part 1's arithmetic. A delta of 40 lines against an 80 kB file is a short letter. A rewrite of half the file is a long one, and at some point you would have been better off sending the book. Slide the edit fraction in the last figure of this part until the letter and the book meet: that meeting is why binaries, and files that churn completely, sit awkwardly in a delta ledger. The first generation mostly declined to solve that. It was built for text that changes a little.
That is the whole of the first generation, stated once. One file, one history file beside it, a lock, a letter of difference, a name stamped into the text. No project, no network, no merge. The next problem is the one the lock refused: two people, two edits, one file, and a history that has to accept both.
Part 2Many hands, one desk
A lock serializes people. Projects do not. The second generation keeps the RCS ledger and changes the rule about who may write: everyone copies, everyone edits, and the system combines the copies. The braid is now allowed. Combining it becomes the product's second half.
Personal copies
Dick Grune, at the Vrije Universiteit in Amsterdam, needed to work with two students on the Amsterdam Compiler Kit's C compiler. One student worked a steady day, the other irregular hours; Grune could work only in the evenings. Their project ran from July 1984 to August 1985. A lock would have meant that whoever was awake owned the file. Grune wrote a set of shell scripts, first called cmt because they let each person commit independently, then renamed Concurrent Versions System. The scripts wrapped RCS. Each person had a personal working copy of every file. You edited yours. When you committed, CVS asked RCS to merge your copy with whatever had landed on the shared desk since you last updated. He posted the scripts on June 23, 1986, to comp.sources.unix.
Brian Berliner, at Prisma, rewrote the scripts in C and added the machinery of releases and vendor sources. Prisma was a third-party shop working on the SunOS kernel, which is to say a group that had to absorb someone else's tree and keep their own changes on top of it. Berliner presented the rewrite at the Winter 1990 USENIX conference in Washington, D.C., as "CVS II: Parallelizing Software Development." On November 19, 1990, CVS 1.0 went to the Free Software Foundation. For the next decade it was the default shared desk of free software, not because it was loved, but because it ran on the network, cost nothing, and let people work at the same time.
The new rule has a name, copy-modify-merge: copy the file without locking it, modify the copy, merge the modified copy with the original. Isolation is the working copy. Combination is the merge. The lock's leftover — a cabinet nobody else can open — is gone. In its place is a conversation the system has to get right.
Three versions, one line
A merge needs three inputs, not two. Call the last shared version the common ancestor. Alice's copy and Bob's copy are two presents grown from that ancestor. For each line, the rule is local and almost boring. If Alice and Bob agree, take that. If Alice matches the ancestor and Bob does not, Bob changed it: take Bob. If Bob matches the ancestor and Alice does not, take Alice. If both differ from the ancestor and from each other, the system cannot decide, and it marks a conflict. That is a three-way merge. Two-way comparison — Alice against Bob, no ancestor — cannot tell a change from a preservation. The ancestor is what makes the braid reversible into a single strand.
Let's do one by hand. A twelve-line file. Alice changes line 3. Bob changes line 9. The ancestor still has the old line 3 and the old line 9, so each side's change is unique and the merge is automatic: the new present has Alice's line 3 and Bob's line 9. Now let both change line 3, differently. The ancestor cannot break the tie. The file that comes back contains both versions, wrapped in conflict markers, and a person has to write the line that will actually go in the ledger. The system produced a recoverable shared history up to the point of disagreement. It did not invent a resolution.
The letter that describes a change, line by line, is still Hunt–McIlroy and Myers underneath. CVS asks diff what Alice did, diff what Bob did, and diff3 how to combine them. The edit graph from Part 1 is now a three-body problem.
The letter in the mail
Before CVS had a network server, the letter was the network. Larry Wall posted patch to the source newsgroups in 1985: a program that takes a diff and applies it to a file on someone else's machine. You did not send the book. You sent the recipe, usually as a unified diff. The recipient's tree either accepted the recipe, producing a new present that matched yours, or it rejected a hunk whose context no longer matched — a protocol check on an incomplete or stale message. Whole communities, the Linux kernel among them for years, lived in this pattern: a maintainer, a mailbox, a series of letters, each letter a delta, the ledger implied by the order of application.
A series of 250 letters is not a curiosity. It is a number Linus Torvalds later put on a typical sync with Andrew Morton. If each letter takes 30 seconds to apply and record, 250 × 30 s = 7,500 s, a little over two hours. If a letter in the middle fails to apply, the letters after it sit on a present that does not exist, and you have a protocol failure in the middle of a braid. The mailbox is a shared medium. It congests. It also, unlike a lock, lets the senders keep working.
Commits that don't finish
CVS inherited RCS's grain: the file. A "commit" of forty files is forty RCS check-ins, one after another. If the process dies at file 23, the desk now holds a tree that no person ever built — 23 files at the new revision, 17 at the old. There is no single number that names the attempt. The ledger, at project scale, has a hole in the shape of a crash. This is the most famous defect of the second generation, and it is a defect of grain, not of people. The product was defined per file in 1972. The project arrived later and was assembled out of files.
Berliner also gave CVS a way to absorb an upstream tree without pretending you wrote it: the vendor branch. You import the vendor's drop as a branch, keep your local changes on another, and merge. It is the braid used as a diplomatic protocol. It works until a file is renamed, because RCS identity is the filename, and a rename looks like a delete plus an add with a fresh, empty history. The letter does not know that a.c is b.c. The ledger forgets.
A star with one center
By the mid-1990s CVS spoke TCP. A repository lived on a server; working copies lived on laptops; update and commit were the two verbs of a star network. The desk was now a machine. That is a different isolation from the working copy: you can edit on a train, but you cannot record a history until you can reach the desk. The server is also a poll. Clients ask, on a timer or a keystroke, whether the desk has moved. Between polls the working copy is a stale photograph of a ledger that is still being written.
The star made the second generation scale across continents, which is why SourceForge and every other public CVS host of 1999 could exist. It also made the desk a single point of delay, of backup, and of corruption. The product — a recoverable shared history — now had a building, a disk, and a password. Lose any of them and the braid of a hundred working copies cannot reconstruct the missing middle, because the working copies hold presents, not the ledger.
The second generation produced something the first could not: a history of a project, kept on a desk that many hands could reach, with a braid that usually combined itself and a person who stepped in when it did not. The grain was still the file. The next system keeps the desk and changes the grain.
Part 3Two central desks
If the defect is grain, the repair is to record a tree as one transaction. Two systems did that work on a central desk, in the same years, for different rooms. Subversion was built to feel like CVS and fix it. Perforce was built for shops that already locked files and shipped binaries. Both produce a reconstructable present of a whole tree. They disagree, load-bearingly, about what a branch is.
All or nothing
In early 2000 CollabNet went looking for a CVS replacement. Their collaboration suite used CVS and had inherited its holes. Brian Behlendorf offered Karl Fogel — author of Open Source Development with CVS — a job to write something better. Fogel was already talking through a design with Jim Blandy. They did not want a new model of collaboration. They wanted CVS without the misfeatures: commits that either land whole or not at all, directories that are versioned, copies and renames that keep history, and a single revision number that names a whole tree. After fourteen months, Subversion became self-hosting on August 31, 2001. Version 1.0 shipped on February 23, 2004.
An atomic commit is a transaction against the ledger. Forty files, a directory add, a rename: either the new tree exists or the old one does. There is no file-23 present. The number that names the attempt is global. Revision 1482 is not "foo.c at 1.17"; it is the whole project at the moment of that commit. Unchanged files are not recopied. They are the same nodes, pointed to by the new tree. The photograph is of the forest, cheaply, because most of the trees did not move.
The working copy, though, is allowed to be mixed. You update src/ and not docs/, and for a while you hold revision 1482 of one directory and 1470 of another. Subversion tracks this on purpose. It is convenient, and it is a new way to be wrong: you can test a present that the ledger never recorded as a single revision. The mixed-revision working copy is a braid inside one person's directory tree.
Copies for free
Branching in CVS was a per-file operation, slow and easy to get wrong. Blandy's design makes a branch a copy of a directory. The copy is a new name pointing at the same node. It takes constant time and constant extra space, regardless of how many files sit under the node. People did not believe this. Blandy recalled telling Cygnus engineers that cutting a branch would be instantaneous; they said they would believe it when they saw it. They saw it. A tag is the same trick: a name for a tree. The braid, at last, is cheap enough to use for a day's work rather than for a year's release.
Let's put numbers on it. A tree of 100,000 files, each file a node. A CVS-style branch that snapshots every file is 100,000 new identities. A Subversion cheap copy is one new directory entry. The history of every file continues through the copy, because the node did not change. Rename is a copy plus a delete of the old name, and because the node is the identity, a.c really is b.c.
The software does not know the words trunk, branch, or tag. Those are a directory convention: /trunk, /branches/1.0, /tags/1.0.0, three names in one repository, the last two made by copying the first. A branch is a folder. Merging is copying changes between folders. Until Subversion 1.5, shipped 19 June 2008, the desk did not remember which revisions had already crossed. Repeated merges re-applied the same letters and conflicted with themselves. Version 1.5 stored that memory in a versioned property, svn:mergeinfo — a list of paths and revision ranges already absorbed. The braid finally had a ledger of its own combining. The property is famously chatty, and later releases spent years teaching it to speak less.
Directories remember
Once the tree is the grain, directories have history too: adds, deletes, properties. The repository is a versioned filesystem. Each commit writes a new root. Jim Blandy described it as a virtual filesystem that tracks tree structure over time. Unchanged children are shared pointers. Changed children are new nodes whose parents, all the way to the root, are new as well — a spine of new directories above a mostly-old tree. The photograph is incremental. The address of the photograph is an integer that counts up.
That integer is a different kind of name from RCS's 1.17. It does not tell you which file changed. It tells you which present of the project you mean. "Get revision 1482" is a complete instruction. "Get foo.c 1.17" was never a complete instruction, because the other files might have been anywhere.
A second central desk
Five years before Subversion's 1.0, Christopher Seiwald's Perforce Software shipped a commercial desk aimed at the same product by a different door. A Perforce changelist is an atomic set of files, numbered, described, submitted as one. The tree lives in a depot — a path namespace that starts with // — and each person maps a slice of that namespace onto a local workspace with a client spec. You do not check out the world. You map what you need. That mapping is why the same desk can hold a million-file game and still give an artist a folder of textures.
The lock comes back as policy, not as the only writer gate. Text can merge. Binaries usually cannot, and Perforce shops treat exclusive checkout as the default for those files: you open the asset, the desk writes your name on it, someone else sees the lock. Forget it on Friday and the leftover is the same leftover as RCS, now sitting on a texture that blocked a build. Subversion made that lock optional around a merge-first tree. Perforce made the lock ordinary around a binary-heavy tree. Same residue, different default.
Classic Perforce branching is integration between depot paths: //depot/main/... and //depot/rel1.0/... are two trees, and p4 integrate schedules the letters that should flow. The relationship is not in the software until someone draws it. Streams, added later, put the relationship in the spec: a mainline, development streams below it, release streams above it, with a rule the graph enforces — merge down, copy up. Less-stable work merges from its parent to stay current, then copies up when it is ready. The braid is no longer a folder you might forget to merge. It is a typed edge.
In 2011 Dan Bloch described Google's Perforce installation as still one server, under a stairwell in Building 43, serving more than twelve thousand users a day, with a lucky engineer having just taken changelist 20,000,000. About 15 million lines a week were changing across about 250,000 files — on the order of rewriting a 2014 Linux kernel, weekly. The desk scaled by mapping, not by cloning. When Google later replaced it with Piper, the migration took years because the workspace-and-changelist shape had grown into every tool around it. Game studios never left. A 40-gigabyte cinematic is a Perforce problem Subversion's line-oriented letter was not hired to solve, and Git's full-tree clone was not eager to download.
The desk as bottleneck
Both stars serialize. You cannot commit on the train. If the desk accepts 2 commits per second and 40 people try to land a change in the same minute, 40 / 2 = 20 s of queue at the peak. Throughput of the product is a property of a machine. Subversion spoke WebDAV to Apache, then svnserve, and moved storage from Berkeley DB to FSFS. It grew a binary delta, svndiff, so a slightly changed image did not cost a full new copy. Perforce treated the large binary as the common case from the start: exclusive opens, lazy workspace sync, integration recorded per file.
By 2002 the kernel's relationship with CVS was already a closed case: Linus Torvalds would not use it. The incident that belongs here is what a per-file ledger does to a tree the size of a kernel, and why a generation that fixed atomicity still could not be the desk that project would accept. Scrub a reconstructed afternoon of a large CVS commit: files landing in whatever order the client sent, a tagged release that does not name a consistent tree, a rename that severs blame.
The desk in the middle, even an atomic one, has a second ceiling: every combination still happens there. The next generation copies the ledger itself — twice, in the same month, as two answers to the same missing desk.
Part 4Two distributed ledgers
A working copy holds a present. A clone holds a history. Once every machine has the ledger, committing no longer waits for a desk, and combining histories becomes a conversation between ledgers. In April 2005 that conversation was invented twice. Mercurial and Git are siblings, not a sequel. They disagree about what a branch is allowed to forget.
Changesets, not files
BitKeeper, built by Larry McVoy's BitMover in the late 1990s, taught a generation of kernel developers to think in changesets. A changeset is a commit as a first-class object: the whole delta of a tree, with parents, with a name, sendable as a letter. BitKeeper stored history per file in SCCS weaves — McVoy called interleaved deltas a brilliant design — but it spoke to users in changesets, and it was distributed: every developer had a repository, not a working copy waiting on a star. Torvalds started using it for Linux in 2002. The license was proprietary, with a no-cost version for open-source projects and a condition that you would not reverse-engineer the protocol.
Perforce had already numbered the same idea on a central desk: the changelist. Subversion numbered the tree. BitKeeper made the numbered change a letter you could send without the desk. That is the move the fourth generation keeps.
The BitKeeper condition is a protocol about a protocol. In early 2005 Andrew Tridgell wrote a client that could talk to BitKeeper servers by watching the wire. McVoy withdrew the free license. On April 6, 2005, Torvalds told the kernel list he would stop using BitKeeper. On April 7 he committed to a new tool, on the tool itself: e83c516, "Initial revision of 'git', the information manager from hell." Twelve days later, on April 19, Matt Mackall announced Mercurial 0.1 to the same list, with the same vacancy as the cause. Torvalds had looked at Monotone, which already named objects by hash, and found it too slow for a tree the size of the kernel. Two ledgers, two weeks, one missing desk.
Two weeks in April
The performance argument was not abstract. Torvalds wrote on April 7, 2005, that if applying and recording a patch took 30 seconds, a 250-letter sync with Andrew Morton would take two hours, and a failure in the middle would be "bad bad bad." BitKeeper had been doing that work in 10–15 seconds per letter. On April 29, Git was measured recording kernel patches at 6.7 per second. 250 / 6.7 ≈ 37 seconds, against 2.08 hours at the 30-second pace. The first merge of multiple Git branches happened on April 18. Kernel 2.6.12 was managed with Git on June 16. Maintainership of Git moved to Junio C. Hamano on July 26, 2005.
Mercurial was not a runner-up. It was a different bet: a small command set, history stored as revlogs — append-only files of deltas with an index, closer to a weave's temperament than to a bag of hashed objects — and no staging area. You commit the working copy. Mozilla ran Firefox on it for nearly two decades. OpenJDK used it. Facebook scaled it until the client became Sapling. The kernel chose Git for local reasons: speed on that tree, the data model Torvalds already had in his head, and twelve days of head start. Parallel invention is a braid. One strand became the default of the forge. The other became the default of several of the largest trees that were not the kernel.
Revlogs and objects
Git's storage is a content-addressed filesystem, an object store. A blob is the bytes of a file, named by the hash of a small header plus those bytes. A tree is a directory listing named by its hash. A commit is a tree, parent hashes, author, message, named by its hash. The name is the content. Duplicate files collapse to one blob. A packfile later stores some objects as deltas against similar neighbors, not necessarily against their parents.
A Mercurial revlog is one file per tracked path, plus a changelog and a manifest, each an append-only sequence of revisions. New data is written at the end. Old revisions stay put. The index says where version 17 begins. Retrieval is closer to SCCS's single-pass temperament than to Git's "hash, then maybe pack." Both compress. They compress different graphs. Git asks "have I seen these bytes?" Mercurial asks "what is the next delta on this file?" Facebook's later scaling work — virtual filesystems, a server-side monorepo, a client that still spoke Mercurial verbs — started from the revlog, not from the object store.
The hash Git used in 2005 was SHA-1: 160 bits, 40 hexadecimal characters. The space has 2160 ≈ 1.46 × 1048 names. A chosen-prefix collision against SHA-1 was demonstrated in public on February 23, 2017. Mercurial used SHA-1 in its nodeids too. Both systems grew newer hashes. The mechanism is the same: if you have the name, you can check that what came back hashes to what you asked for.
On April 16, 2005, nine days after Git hosted itself, Torvalds imported Linux 2.6.12-rc2 as commit 1da177e: 17,291 files, 6,718,755 insertions. That is about 388 lines per file if you average blindly, and 6.7 million lines of present in one letter. He did not import the earlier history. The product, on that Saturday, was a reconstructable past that began at 2.6.12-rc2, on purpose.
Four names for a strand
Git's branch is a movable name for a commit. The name lives outside the object. Delete the name and the commits remain until garbage collection, if nothing else points at them. Two names on the same commit is cheap. Checking out a commit without a name is the "detached HEAD" that Git warns about, because the next commit might become hard to find.
Mercurial baked a different name into the changeset itself: the named branch. Every commit records which branch it was made on. The default name is default. The name never moves; new commits on that branch add to it. That is useful for a long-lived release line you want to audit in ten years, and noisy if every feature gets a permanent name. Mozilla's Firefox trees mostly refused named branches for features. They used separate repositories as channels — mozilla-central, beta, release — and later a unified repository whose bookmarks pointed at each channel's head. A bookmark is Mercurial's Git-like name: a pointer that slides, not a field inside the commit. Mercurial also lets you commit without a bookmark at all. Heads do not need labels. Git heads do, or they risk being swept.
Phases are Mercurial's rewrite rule. Draft commits may be rebased; public commits may not. Publishing is a one-way door. Git's equivalent is social — a protected branch on a forge, a refusal to force-push — not a property of the object. The two systems produce the same product. They hide the braid in different places: Git in a file of names, Mercurial in the changeset and, if you want the Git workflow, in a bookmark beside it.
This is why distributed ledgers do not need a serializer in the middle of every commit. Alice commits locally; Bob commits locally; their graphs diverge; later a letter moves, and one of them ties the braid. The star is optional. It is a convenience for publishing, not a condition for recording.
Letters at scale
A clone copies the ledger. A fetch copies new objects from a remote. A pull fetches and then ties the braid. A push offers your new objects to another ledger, which accepts them if they fast-forward its names, or refuses if they would silently drop a strand. Mercurial's verbs are the same idea with fewer nouns: hg pull, hg push, hg merge. The refusal is the product protecting itself. Force-pushing is how Git overrides the protection. Mercurial's phases try to make the override unnecessary: once public, the strand does not slide out from under someone else.
The leftover of a Git force-push is a commit that still exists, often, in a reflog — a local diary of where a name used to point, kept for weeks. It is an orphaned commit until garbage collection sweeps it. Residue, again: a past the desk no longer names but the machine has not forgotten.
Signing a commit puts a cryptographic identity inside the object. Verifying it is another checksum, on the person rather than on the bytes. At the object store the defenses are already two deep: the hash names the content, the signature names the author of that name.
The fourth generation produced the product in a form that can leave a building. What it did not produce, by itself, is a place everyone agrees to send to — or a single answer to what a branch is. Those answers still live side by side: a Subversion folder, a Perforce stream, a Mercurial name inside a commit, a Git pointer on the side.
Part 5Four kinds of branch
A distributed ledger still needs a shared present — not a single server that records every commit, but a name everyone uses when they mean the project. The forge is that name for Git and, for a while, for Mercurial. Subversion and Perforce never needed it in the same way: the desk already had a name. The interesting disagreement in 2026 is not which website wins. It is that four living systems still mean four different things by the word branch.
The forge
GitHub opened to the public on April 10, 2008, with the line "Social Code Hosting." Tom Preston-Werner, Chris Wanstrath, and PJ Hyett built it for a Ruby community that had already started to like Git. Rails moved over near launch. Bitbucket opened the same year for Mercurial; it added Git in 2011, a date that is easy to read as a verdict. SourceForge and Google Code had already been Subversion desks. The star came back as a convention. You can still clone from anyone. In practice you clone from the named URL, because that is where the names are.
A pull request is a letter with a waiting room. You push a strand, ask the named desk to tie it, and other people write on the letter before anyone merges. Bitbucket did the same for Mercurial. Subversion and Perforce shops more often review a changelist or a revision still sitting on the central desk. The three-way merge still runs. What the forge added is a protocol around it: review, status checks, a button. Rejecting the request leaves your strand intact. That is the product being careful in public.
How a branch is a branch
Put the four namings on one table, because they are the through-line this essay has been building.
Subversion: a branch is a cheap copy of a directory. The convention /trunk, /branches, /tags is social. Merge tracking, after 1.5, is a property on the copy. Delete the directory and the copy is gone from the tree, though old revisions still hold it.
Perforce: a classic branch is two depot paths with integration history between them. A stream is a path plus a parent plus a type. Merge down, copy up. The graph tells you where the letter is supposed to go. Exclusive opens keep unmergeable files from growing a braid they cannot combine.
Mercurial: a named branch is a field inside the changeset, permanent, auditable, easy to clutter. A bookmark is a sliding pointer, closer to Git, optional. Phases stop you rewriting what you have already published. Firefox treated whole repositories as channels, then bookmarks in a unified repo, and in 2023 announced a move of the source of truth to Git, with the developer-facing cutover expected 30 April 2025 — not because revlogs failed, but because two SCMs had become a burden.
Git: a branch is a file containing a hash. Cheap to make, cheap to delete, silent about which strand a commit was born on unless you keep the name. The forge's protected branch is how that silence gets policy.
None of these is a wrong braid. They are different prices for the same product: a reconstructable past, and a way to combine pasts that diverged. The directory copy is easy to explain and hard to merge until mergeinfo. The stream graph is policy in the software. The named branch remembers too much for feature work. The pointer remembers too little for archaeology unless the forge keeps the names.
hg bisect is the same operation — a use of the product that only exists because the past is reconstructable and ordered.Let's put that search in units. Fourteen checkouts to find one failing change among 16,384 is why bisect is a reason to keep history linear enough to search. A braid with merge commits still searches, with more care. A history that was rewritten to hide the failure cannot. Recoverability is not a feeling. It is an operation with a step count.
The installed base
Tools do not replace each other the way papers do. They replace each other the way kitchens do. Subversion remains the desk of places that wanted a star on purpose — a single policy, a single backup, no force-push. Perforce remains the desk of game studios and other binary-heavy shops, and it was Google's desk for eleven years before Piper. Mercurial remains in the tools Facebook grew out of it, and in trees that have not finished a Git migration. Git is the default of the forge, which is the default of the course, which is the default of the next project.
A stock-and-flow of that installed base is the honest picture of 2026. Inflow: new repositories, almost all Git, almost all born on a forge. Stock: decades of ledgers in every encoding from this essay, including Perforce depots that never showed up in public clone counts. Outflow: conversions that are lossy in the ways Parts 2 and 3 named. The product is only as reconstructable as the encoding you still have a reader for.
Some artifacts outgrew the working-copy-plus-clone assumption. Google's Piper and other monorepo systems keep a tree so large that cloning it is the expensive joke, and the working copy is a sparse view onto a desk that is, again, central — the Perforce mapping idea with different internals. Git grew shallow clones, sparse checkouts, and partial clones so that a present can be fetched without the whole past. The fourth generation, at the limit of size, reimports a little of the third.
What still fails
The combining still fails in the ways Part 2 taught. Two edits to the same line still need a person. A Git rebase still rewrites names. Mercurial phases refuse the same rewrite once a commit is public. A force-push still drops a shared present. The defenses stack, and they peel: hash checks, signed commits, protected branches, required reviews, exclusive opens, a reflog on the machine that did the damage. No layer is the product. Each layer is a way the product survives a particular lie.
The whole path, from a keystroke to a reconstructable past other people can fetch, is now long enough to scrub as one motion: edit, stage if you are on Git (Mercurial skips that noun), commit, push or submit, review, merge, fetch, checkout. Each step is a mechanism from an earlier part.
The last figure is a small desk you can lose. Two people, one file, the rules this essay has named. You may lock as Perforce often does, or copy-modify-merge as Subversion and the distributed systems do. You may commit atomically or per file. You may push to a shared name or only keep a local ledger. The ways to lose are the ways the product fails.
Final words
The system produces a recoverable shared history of a changing text, and a way to combine histories that diverged. It learned to do the first half by storing letters instead of books, then by photographing whole trees at once, then by naming photographs after bytes or appending them to a revlog. It learned to do the second half by forbidding it with a lock, then by allowing it with a three-way merge, then by making the braid a directory copy, a stream edge, a named field, or a sliding pointer.
None of those steps retired the earlier ones. Subversion, Perforce, and Mercurial are not prehistory. They are still how a large fraction of the world's trees remember themselves. A delta is still a letter. A working copy is still a present. A merge is still three versions of the same line. If you scroll back, the figures are still there, and they still do the arithmetic. The product is what they produce when they work, and what they try to give back when they do not.
Sources
Primary papers and contemporaneous documents
- Marc J. Rochkind, "The Source Code Control System," IEEE Transactions on Software Engineering, vol. 1, no. 4, Dec. 1975, pp. 364–370.
- Marc J. Rochkind, "A Retrospective on the Source Code Control System," IEEE Transactions on Software Engineering, vol. 51, no. 3, Mar. 2025, pp. 695–699.
- Marc J. Rochkind, account of the weave's invention, TUHS mailing list, 10 Nov. 2015; archived at sccs.sourceforge.net/sccs_invention.html (Wayback).
- Walter F. Tichy, "Design, Implementation, and Evaluation of a Revision Control System," Proceedings of the 6th International Conference on Software Engineering, 1982, pp. 58–67; Purdue CS TR 81-397.
- Walter F. Tichy, "RCS — A System for Version Control," Software: Practice and Experience, vol. 15, no. 7, July 1985, pp. 637–654.
- James W. Hunt and M. D. McIlroy, "An Algorithm for Differential File Comparison," Bell Laboratories Computing Science Technical Report 41, 1976.
- Eugene W. Myers, "An O(ND) Difference Algorithm and Its Variations," Algorithmica, vol. 1, 1986, pp. 251–266.
- Dick Grune, CVS shell scripts posted to
comp.sources.unix/mod.sourcesvolume 6, 23 June 1986 (headers also recorded 3 July 1986 PST); original history at dickgrune.com/Programs/CVS.orig. - Brian Berliner, "CVS II: Parallelizing Software Development," Proceedings of the Winter 1990 USENIX Technical Conference, Washington, D.C., pp. 341–352.
- Karl Fogel and Ben Collins-Sussman et al., Version Control with Subversion (svnbook), "Subversion's History," cheap copies, mixed-revision working copies, and merge tracking (
svn:mergeinfo, 1.5). - Subversion 1.5.0, 19 June 2008 — merge tracking; Apache Subversion blog, "Mergeinfo — Understanding the internals," 6 May 2008.
- Dan Bloch, "Still All On One Server: Perforce at Scale," 2011 — Google's single Perforce server, >12,000 users/day, changelist ~20,000,000.
- Perforce Software / Helix Core documentation: changelists, depots, client workspace maps, streams, "merge down, copy up."
- Matt Mackall, "Mercurial v0.1 — a minimal scalable distributed SCM," Linux kernel mailing list, 19–20 Apr. 2005.
- Mozilla version-control docs: named branches vs bookmarks; Firefox Git migration announcement (Nov 2023) and expected developer-facing cutover 30 Apr. 2025.
- Facebook Sapling documentation (bookmarks, scaling from Mercurial).
- Jim Blandy, "Subversion," Linux Journal, January 2002 (written August 2001): self-hosting, versioned filesystem, cheap branches.
- Linus Torvalds, Linux Kernel Mailing List, 6–20 April 2005 (BitKeeper withdrawal; Git announcement; 30 s × 250 mail arithmetic).
- Git commit
e83c5163316f89bfbde7d9ab23ca2e25604af29, 7 Apr. 2005, 15:13:13 −0700, "Initial revision of 'git', the information manager from hell." - Git commit
1da177e4c3f41524e886b7f1b8a0c1fc7321cac2, 16 Apr. 2005, "Linux-2.6.12-rc2" (17,291 files, 6,718,755 insertions). - GitHistory, git.wiki.kernel.org: first merge 18 Apr. 2005; 6.7 patches/s on 29 Apr. 2005; kernel 2.6.12 on Git 16 June 2005; Hamano maintainership 26 July 2005.
- Matt Mackall, "Mercurial v0.1 — a minimal scalable distributed SCM," Linux kernel mailing list, 19–20 Apr. 2005.
- git-scm.com/about — kernel working tree ~1.7 GB, history pack ~5.5 GB as of 2025; Stack Overflow 2022 figure that 96% of professional developers use Git.
- Pro Git (Scott Chacon and Ben Straub), object model, packfiles, reflog expiry (30 / 90 days).
- Eric S. Raymond, "Understanding Version-Control Systems" (draft), catb.org — generation table and CVS critique.
- POSIX / Open Group
whatand SCCS utilities; Programmer's Workbench Unix, SCCS version 4, 18 Feb. 1977. - GitHub public launch, 10 Apr. 2008.
- Microsoft to acquire GitHub for $7.5 billion in stock, announced 4 June 2018; GitHub then reported on the order of 28 million developers.
- GitHub Octoverse 2024 — github.blog/news-insights/octoverse/octoverse-2024: 5.2 billion contributions, more than 518 million projects; 100 million developers marked in early 2023.
- GitHub Octoverse 2025 coverage (GitHub Universe / Octoverse 2025): community above 180 million developers; on the order of 230 new repositories per minute (use the Octoverse report itself, not secondary round-ups, when implementing the figure).
- Phoronix GitStats on the kernel tree, 31 Dec. 2024: about 1.32 million commits, ~87k files, ~39.8 million lines of tracked text.
- git-scm.com/about and contemporaneous clone measurements: uncompressed objects on the order of 10² GB, packfiles of a few GB after
git gc. - Tertiary "history of Git" blog posts that disagree on whether Git's first commit was 3 Apr. or 7 Apr. 2005 — prefer the commit timestamp and LKML.
- Invented market-share percentages for CVS/SVN/Git in any given year.
- Blockchain-as-ledger analogies; CI/CD throughput as if it were version control.