Often if you see a block diagram like this, what comes to mind is a compatability layer in between a program and several operating systems. Generally something that's general-purpose like java, or a web browser, or a widget toolkit.

-------------
|           |
|           |
-------------
|           |
-------------
|  |  |  |  |
-------------

(Generally it's drawn up all purty, but I'm lame.)

But lately I've seen and written a lot of code where the diagram is more complex:

-------------
|           |
|  program  |
|           |
|  |  |  |  |
-------------
| V| C| S|  |
-------------
|    OS     |
-------------

Sometimes the program code is littered with multiple switch statements, as in debcheckout, debcommit, and etckeeper.

case "$vcs" in
git)
svn)
hg)
esac

Sometimes it pushes the VCS-specific code into modules.

use IkiWiki::Rcs::$rcs;
rcs_commit();

But if it does, these modules are specific to that one program. This isn't a general-purpose library. dpkg source v3 doesn't need to use the VCS is the same way as ikiwiki, and even ikiwiki's rcs_commit is very specific to ikiwiki, in its error handling, conflict resolution, locking, etc.

pristine-tar injects and extracts data directly from git, using low-level git plumbing, in a way that probably can't be done at all with other VCSes. But even as I was adding that low-level, very git-specific code into pristine-tar, I found myself writing it with future portability in mind.

if ($vcs eq 'git') {
    # git write-tree, git update-index, and other fun
}
else {
    die "unsupported vcs $vcs";
}

When Avery Pennarun talks about git being the next unix, he's talking about programs like these, that build on top of a VCS.

But if git is the next unix, then so is mercurial, so is darcs, so is bzr, so too even svn (unless it's Windows?). In other words, we're back to the days when every program had to be ported to a bunch of incompatible and not-quite-compatible operating systems. Back to the unix wars.

In Elija's discussion of the "limbo" VCS state he gives several great examples of how multiple VCSes that each seem on the surface to offer similar commands like "$vcs add" and "$vcs commit" can behave very differently.

echo 1 > foo
$vcs add foo
echo 2 > foo
$vcs commit

What was committed, "1" or "2"? Depends on which $vcs you use.

Compare with unix where open(2) always opens a file, perhaps with different options, or different handling of large files, but portably enough that you generally don't need to worry about it. Even if you're porting to Windows, you can probably get away with a compatability layer to call whatever baroque monstrosity Windows uses to open a file, and emulate open(2) close enough to not have to worry about it most of the time.

A thin compatability layer that calls "$vcs add" isn't very useful for a program that builds on top of multiple VCSes. mr is essentially such a thin compatability layer; it manages to be useful only by being an interface for humans, who can deal with different limbo implementations and other quirks.

The VCSes are to some degree converging, but so far it's mostly a surface convergence, with commands that only look the same. Where will things go from here?

  • Maybe there will be a standardisation effort like POSIX for VCSes. Though it seems harder; VCSes have a wider interface than just syscalls and filesystems, so there's more scope for incompatibility.
  • Or will complicated compatability code like cygwin be developed, to let a program that was written for git use bzr instead, carefully hiding all the differences?
  • Another option would be that one VCS wins. So far I'm seeing some consolidation, but little indication that one VCS will emerge as the choice for everyone.
  • Maybe the VCSes might begin to support each other's repositories. If a program only supports git, and you use svn, that's fine, if git can transparently access the svn repo.
  • Or will we go on for decades spending a lot of time on portability code?