$ cat ~/blog/from-sourcesafe-to-git.md

from sourcesafe to git

2026-11-10·4 min read

A river of light flowing from a padlocked card cabinet, through drifting files and a glowing tree, into a branching emerald graph

Git feels like it has always been here. It hasn't. Over my career I've lived through four source control systems — Visual SourceSafe, CVS, Subversion, and Git — and helped carry code from each one into the next. Those are the "merge" markers you'll see in the timeline on my about page.

What stuck with me isn't the commands. It's that every one of these tools quietly encoded a theory of how people should work together — and when the tool changed, the team changed with it.

sourcesafe: one person, one file, one lock

Visual SourceSafe worked like a library. You checked out a file, and while you had it, nobody else could edit it. When you were done, you checked it back in and released the lock.

That sounds safe, and for a small team it mostly was. But it meant work was serialized around whoever was holding the lock — and if they went home for the weekend with a file checked out, everyone else waited. The database itself lived on a shared network drive, which made it fragile in ways that anyone who has run SourceSafe's repair utility will remember.

The lesson: a lock is a coordination tool pretending to be a safety tool. It didn't prevent conflicts so much as push them onto people's calendars.

cvs: everyone edits, the tool merges

CVS flipped the model to copy-modify-merge. Everyone works on their own copy at the same time, and the tool merges changes when you commit. If two people touched the same lines, you resolved the conflict by hand.

$ cvs update
M src/Billing.cs
C src/Invoice.cs   # conflict — your turn

That was a big step for parallel work. But CVS versioned each file separately. There was no such thing as an atomic commit across the whole project, so a commit that died halfway could leave the repository in a state that never existed on anyone's machine. Renaming a file meant losing its history, which quietly discouraged people from fixing bad names.

The lesson: trust needs atomicity. If a change can land halfway, people stop believing what's in the repository.

subversion: "cvs done right"

Subversion, which reached 1.0 in 2004, set out to fix exactly those problems. Commits were atomic. The whole repository had one revision number, so "it worked at r4120" meant something precise. Directories and renames were versioned. Branches and tags were cheap copies, laid out by convention:

/trunk
/branches/release-2.1
/tags/v2.1.0

For years this was a great place to be. The rough edge was merging: proper merge tracking only arrived in 1.5 in 2008, and before that, merging a long-lived branch back meant keeping track of revision ranges yourself. Teams learned to branch rarely and merge carefully — which is a habit, not a law of nature.

The lesson: what a tool makes expensive, teams stop doing — even when it's the right thing to do.

git: every clone is the whole history

Git came out of the Linux kernel community in 2005 and threw out the idea of a single central server you have to ask permission from. Every clone is a full repository. Commits, branches, and history work offline. Branching is so cheap that it stops being an event and becomes the default way to work:

$ git switch -c fix/invoice-rounding
$ git commit -am "Round invoice totals half-even"
$ git push -u origin fix/invoice-rounding

That one change in cost reshaped how teams collaborate. Short-lived branches, pull requests, code review on every change, CI that runs before anything merges — almost everything we now call a normal workflow depends on branches being nearly free.

The lesson: make the right thing cheap, and people will do it on their own.

what carried over

Each migration was mostly a people project wearing a technical costume. Moving the code was the easy part. The real work was helping a team unlearn habits the old tool had trained into them — waiting for locks, avoiding renames, fearing merges — and trusting the new model enough to work differently.

I didn't do any of those migrations alone, and I'm grateful to the teams who put up with each cutover. But I still think about those four tools whenever I design a system today, including the AI ones I work on now. The question is always the same: what does this system make easy, what does it make expensive, and what will people do because of it?

Git won't be the last one, either. Something will eventually make today's workflow look as quaint as asking a coworker to check a file back in.