From Punchcards to Pull Requests: A History of Version Control
The long and winding road from RCS to Git, and why controlling change is computing's hardest problem
The Problem of Change
Software is, by its nature, mutable. Unlike a bridge or a building, a program is expected to change continuously throughout its life. New features are added, bugs are fixed, requirements evolve. Managing this change — tracking what changed, when, by whom, and why — is one of computing's oldest and most important problems.
The tools we use to manage change are called version control systems (VCS), and their evolution mirrors the evolution of software development itself. From physical artifacts to distributed networks, the history of version control is a history of how programmers learned to collaborate.
The Pre-Digital Era: Physical Version Control
Before computers, version control was literal. Engineers kept numbered drawings in plan rooms. Writers used draft numbers. Lawyers marked documents with revision dates. The basic concept — tracking changes over time — predates computing by centuries.
In the earliest days of computing, "source code" was a physical object: a deck of punch cards. Version control meant keeping previous decks in labeled boxes. If you needed to revert a change, you literally swapped one deck for another. This was version control at its most tangible, and its most terrifying — drop a deck of cards, and your program was scrambled.
As programming moved to terminals and time-sharing systems in the 1960s, source code became files on disk. But version control practices lagged behind. The most common approach was manual file copying: program.c, program.c.bak, program.c.old, program.c.FINAL, program.c.FINAL2. This approach survives to this day in non-programming contexts (every desktop has a report_final_FINAL_v3.docx), and it is terrible.
SCCS: The First Version Control System (1972)
The first true version control system was SCCS (Source Code Control System), written by Marc Rochkind at Bell Labs in 1972. SCCS tracked changes to individual files using a technique called interleaved deltas — rather than storing complete copies, it stored the original file plus the differences (deltas) for each revision.
SCCS introduced concepts that persist to this day:
- Revisions identified by numbers (1.1, 1.2, 1.3)
- Lock-modify-unlock workflow: check out a file (locking it so no one else can edit it), modify it, check it back in
- Change history: who changed what, when
The lock-based model was SCCS's defining characteristic — and its greatest limitation. Only one person could edit a file at a time. In small teams, this was manageable. As teams grew, it became a bottleneck.
RCS: Refinement (1982)
RCS (Revision Control System), written by Walter Tichy at Purdue University in 1982, improved on SCCS in several ways. It stored deltas more efficiently (using reverse deltas — keeping the latest version intact and computing older versions by applying reverse patches). It was faster. And it became the standard on BSD Unix systems.
But RCS shared SCCS's fundamental limitation: it was file-centric. Each file had its own independent revision history. There was no concept of a project-wide "version" or a coherent snapshot of all files at a point in time. If you had 100 files in your project, you had 100 independent revision histories with no way to group them.
CVS: The Networked Revolution (1990)
CVS (Concurrent Versions System) was created by Dick Grune in 1986 as a set of shell scripts wrapping RCS, and later rewritten in C by Brian Berliner in 1989. CVS was revolutionary for two reasons:
First, it introduced the copy-modify-merge model, replacing lock-modify-unlock. Multiple developers could edit the same file simultaneously. When they committed their changes, CVS would attempt to merge them automatically. If the changes conflicted, the developer was asked to resolve the conflict manually.
This was a philosophical shift. SCCS and RCS assumed that concurrent editing was dangerous and must be prevented. CVS assumed that concurrent editing was normal and must be managed. This assumption — that collaboration is the default, not an exception — underlies every modern VCS.
Second, CVS was client-server. A central repository lived on a server, and developers checked out working copies to their local machines. This enabled distributed teams to collaborate over networks — a crucial capability as the internet grew.
CVS dominated through the 1990s and into the early 2000s. The Apache Software Foundation, the FreeBSD project, and countless other open-source projects used it. But its limitations were significant: atomic commits were impossible (if a commit of multiple files failed halfway, the repository was in an inconsistent state), renaming files was not tracked, and branching was slow and painful.
Subversion: CVS Done Right (2000)
Subversion (SVN) was created by CollabNet (with Karl Fogel and Ben Collins-Sussman leading development) as a deliberate "better CVS." Released in 2000, it fixed CVS's worst problems:
- Atomic commits: All files in a commit succeed or fail together
- Directory versioning: Renames, moves, and directory changes are tracked
- Efficient branching: Branches are cheap copies, not expensive duplications
- Binary files: Proper support, unlike CVS
Subversion's mental model was simple: a central repository with a linear history of revisions, each identified by a monotonically increasing number (r1, r2, r3...). Branches and tags were just directory copies within the repository, a design that was elegant but conceptually confusing for newcomers.
SVN became the dominant VCS for enterprise software development in the 2000s. Google used a massive SVN-like system (Perforce, then their custom Piper) for years. Apache migrated from CVS to SVN. For many developers, SVN was "good enough" and might have remained dominant indefinitely.
Then came Git.
Git: The Distributed Revolution (2005)
Git was born from a crisis. The Linux kernel project had been using BitKeeper, a proprietary distributed VCS, for free since 2002. In April 2005, the free license was revoked after allegations that a Linux developer had reverse-engineered the BitKeeper protocol. Linus Torvalds, needing a replacement immediately, decided to write his own.
He started coding on April 3, 2005. By April 7, Git was self-hosting (managing its own source code). By April 29, Git was benchmarked as faster than BitKeeper at merging Linux kernel patches. The speed of development was astonishing, but then Torvalds had designed it to solve a problem he understood intimately: managing the world's largest collaborative software project.
Git's design was radically different from everything before it:
- Distributed: Every developer has a complete copy of the repository, including full history. There is no central server (though teams typically designate one by convention).
- Content-addressed: Every file, directory, and commit is identified by a SHA-1 hash of its contents. This makes the history tamper-evident and enables efficient storage.
- Branching is trivial: Creating a branch is creating a pointer. It takes milliseconds regardless of repository size.
- Merging is first-class: Git's merge algorithms were designed by people who merged thousands of patches per release cycle.
The conceptual model was a directed acyclic graph (DAG) of commits, where each commit points to its parent(s). Branches are just named pointers into this graph. Merges are commits with two parents. This model is mathematically clean and enables workflows (rebasing, cherry-picking, octopus merges) that are impossible or impractical in linear VCS systems.
GitHub: Social Coding (2008)
Git was powerful but hostile to newcomers. Its command-line interface was (and is) notoriously confusing. GitHub, launched in February 2008 by Tom Preston-Werner, Chris Wanstrath, PJ Hyett, and Scott Chacon, changed everything by wrapping Git in a web interface and adding social features.
GitHub's killer feature was the pull request — a mechanism for proposing, reviewing, and discussing changes before merging them. Pull requests made code review accessible and visible. They turned collaboration from a technical process into a social one.
GitHub grew explosively. By 2013, it hosted 10 million repositories. By 2018, when Microsoft acquired it for $7.5 billion, it hosted 100 million. By 2024, over 300 million. GitHub didn't just host open-source projects — it became the platform where open source happened.
Modern Version Control
Today, Git is the overwhelmingly dominant VCS. The 2023 Stack Overflow Developer Survey found that over 93% of developers use Git. The remaining percentage is split among SVN, Mercurial, and others.
But version control continues to evolve:
- Monorepo tools like Google's Piper and Meta's Sapling address Git's scaling limits for enormous repositories.
- Git LFS (Large File Storage) extends Git to handle large binary files that would otherwise bloat the repository.
- Conventional Commits and semantic versioning standardize commit messages and release numbering.
- GitOps applies version control to infrastructure, using Git as the source of truth for deployments.
The Distributed Revolution
The shift from centralized to distributed version control was the most significant architectural change in the field's history. Centralized systems (CVS, Subversion, Perforce) require a connection to the central server for most operations: committing, viewing history, branching, and merging all require network access. If the server is down, development stops. If the server is lost and backups are stale, history is gone.
Distributed systems (Git, Mercurial, Bazaar) give every developer a complete copy of the repository, including full history. Commits, branches, logs, and diffs are local operations that complete in milliseconds without network access. Synchronization between repositories happens explicitly through push and pull operations.
The distributed model solved several practical problems simultaneously. Developers could work offline (on planes, in cafes, in locations with unreliable internet). Feature branches were cheap enough to create for every task. Merging, which was painful in centralized systems, became a routine operation. And the full history on every machine provided natural backup: if the "central" server (which was just a convention, not a requirement) was lost, any clone could replace it.
Mercurial, created by Matt Mackall in 2005 (the same month Git was started, also in response to the BitKeeper crisis), offered a more user-friendly alternative to Git. Mercurial's command set was more consistent, its interface was more approachable, and its documentation was better organized. For several years, Mercurial and Git competed for adoption. Git won, primarily because GitHub created a social platform that generated network effects Mercurial could not match. Sun/Oracle chose Mercurial for OpenJDK, Facebook used Mercurial at massive scale, but the broader open source community standardized on Git.
The Pull Request and Code Review
The pull request (PR), invented by GitHub as a workflow convention layered on top of Git's merge capabilities, transformed software collaboration. Before pull requests, contributing to an open source project meant sending a patch to a mailing list and hoping a maintainer would notice it. The process was intimidating, opaque, and unfriendly to newcomers.
Pull requests created a structured, visible, and inclusive workflow. Fork the repository, make changes on a branch, open a PR with a description, receive feedback through inline comments, update the code, and merge. Each step is documented, auditable, and accessible through a web interface. The PR serves simultaneously as a change proposal, a discussion forum, a code review record, and an audit trail.
Code review, once a formal process practiced mainly at large organizations, became universal through pull requests. Even solo developers open PRs against their own repositories to maintain a review habit and create documentation of decisions. The PR-based workflow is now so standard that it shapes how teams are organized, how work is tracked, and how quality is maintained.
The DevOps Revolution and Infrastructure as Code
Version control s influence expanded beyond source code into infrastructure and operations, catalyzing the DevOps movement. Infrastructure as Code (IaC) tools (Terraform, Ansible, CloudFormation, Pulumi) allow infrastructure configurations to be stored in version-controlled repositories. Server configurations, network topologies, database schemas, and deployment pipelines are all expressed as text files and managed with the same Git workflows used for application code.
This convergence of development and operations practices created new workflows. GitOps uses Git as the single source of truth for both application code and infrastructure state. Changes to production infrastructure are proposed through pull requests, reviewed by teammates, tested in CI, and applied through automated pipelines. Rolling back a failed infrastructure change is as simple as reverting a Git commit. Tools like ArgoCD and Flux CD implement this pattern for Kubernetes deployments.
Continuous Integration (CI) automates the process of building and testing code on every commit. Continuous Deployment (CD) extends this to automatically deploy tested code to production. Together, CI/CD pipelines transformed deployment from a manual, error-prone, weekly (or monthly) ceremony into an automated, reliable, hourly (or per-commit) process. GitHub Actions, GitLab CI, Jenkins, and CircleCI are the dominant CI/CD platforms, each building on version control as the trigger mechanism.
The monorepo approach (storing an organization s entire codebase in a single repository) pushed version control systems to their limits. Google s Piper repository contains billions of files and petabytes of data. Facebook s Mercurial-based repository required significant custom engineering to handle its scale. These extreme use cases drove innovations in virtual filesystems (GVFS, EdenFS), sparse checkout, partial clone, and commit graph caching that are now making their way into mainstream Git. Microsoft s migration of Windows to Git (the largest Git repository in the world) required the development of VFS for Git (now Scalar), demonstrating both Git s flexibility and the engineering effort required to adapt it to extreme scale.
The lesson from this history is that tools shape practices as much as practices shape tools. Cheap branching made feature branches possible. Distributed repositories made offline work and open source collaboration practical. Pull requests made code review universal. Each tool innovation unlocked workflows that were previously impractical.
Key Takeaways
- Version control has evolved from physical media (punchcards, tapes) through centralized systems (RCS, CVS, Subversion) to distributed systems (Git, Mercurial).
- Each generation solved problems created by the previous one: RCS added automatic diffing, CVS added concurrent access, Subversion added atomic commits, Git added distributed operation.
- The shift to distributed version control (Git, Mercurial) was driven by practical needs: offline work, cheap branching, better merging, and natural backup through replication.
- Git won the DVCS competition primarily through GitHub's network effects, not through technical superiority over Mercurial.
- The pull request, invented by GitHub as a social convention on top of Git's merge mechanics, transformed software collaboration and made code review universal.
The Deeper Pattern
The history of version control reveals a consistent pattern: each generation solves the previous generation's scaling problem. SCCS scaled from no version control to single-file tracking. CVS scaled from single-developer to multi-developer. SVN scaled from informal to atomic operations. Git scaled from centralized to distributed.
Each step required not just new technology but a new mental model. The shift from lock-based to merge-based thinking. The shift from central to distributed. The shift from version numbers to content hashes. These conceptual shifts were harder than the technical ones.
The next frontier is likely AI-assisted version control — systems that can automatically resolve merge conflicts, suggest reviewers, predict which changes are risky, and maintain consistency across vast codebases. The tools will change. The fundamental problem — managing change in a collaborative environment — will endure as long as software exists.
From punch card decks in labeled boxes to distributed hash graphs replicated across the globe, version control tells the story of how programmers learned to work together. It's a story that's far from over.