During a Twitter exchange about committing frequently, I encountered this comment:

I don’t like to see people create obstacles for themselves. You do not need to use whatever git bridge happens to exist for whichever version control system you feel trapped using. I made the same mistake when I started learning about this stuff. I came to git from Subversion (svn), and I insisted on using git-svn for a while. If you don’t know it, git-svn “connects” your git repository to your svn repository, and when you “push” from git to svn, the bridge creates a svn commit for every git commit. This essentially allows you to “batch up the pain” from working with svn (expensive branching, for example), suffering only when you absolutely need to publish to your svn repository. You could do everything in git, then publish those changes in one big batch to svn, making yourself a relaxing coffee during the several minutes it takes to copy your recent git history into svn.

This assumes, of course, that you want your svn history to match your git history. At the time, I didn’t need it, and the people around me didn’t want it.

Maybe you find yourself in this situation:

  • You want to use git for personal version control.
  • You want to commit very frequently, such as on every green bar. Maybe you’re doing this as an experiment; maybe you prefer to work this way and the people around you don’t.
  • The people around you don’t want you to commit frequently, perhaps because they’ve tried that in the past and got lost in all the micro-commits or suffered from people committing bad code.
  • The people around you don’t want to or don’t feel that they have the authority to use git.

In this situation, you don’t need to—and probably shouldn’t—use the git bridge to your other version control system. You don’t want your svn (or p4 or ClearCase) history to match your git history. Instead, you simply want to use git for personal version control (the programmer’s “undo” button) and the team’s system only when you want to publish changes to the team. No special tools required.

In short, you can put your git repository inside your current working copy, then commit to each of them separately, just as long as you ignore the git resources in your team’s repository and ignore the svn/p4/ClearCase resources in your git repository. It really works. Intrigued? Read on.

Getting Started

If you haven’t thought of this before, don’t feel bad. Neither did I, even though it seemed obvious once I saw it. You can start right now without the risk of messing up your team. Go into your working copy. Before you change anything, update your working copy and make sure that you have no uncommitted changes. (It still surprises me how often we forget this crucial step.) Now you can safely experiment.

From the root of your working copy, create a git repository.

OurAwesomeProject $ git init .

This creates the .git directory. Since you don’t categorise this as a project source artifact, you don’t want it in your svn (or p4 or ClearCase) repository, so add it to your svn repository’s “ignore list”. (This command, of course, will depend on which version control system your project uses.)

OurAwesomeProject $ svn propedit svn:ignore .git

If you need to commit this property change, then do that now. (I hope you need to. A sensible version control system would treat this as a change that needs committing.)

Now what do you put in your git repository? All the same artifacts in your svn/p4/ClearCase repository except for any svn/p4/ClearCase metadata. In the case of svn, this means the .svn directories. Add those to your new git repository’s .gitignore list. For svn, for now, it suffices to create a file with the single entry “.svn”. Since this creates a new artifact in your git repository, commit the new file.

OurAwesomeProject $ git add -A && git commit -m "Now ignoring the Subversion repository"

Now you can safely commit changes to git and svn independently. Of course, you have to remember to commit changes to git and svn independently, but with a few days of practice, that will become second nature.

The New Workflow

With this simple structure in place, this becomes my workflow:

  1. Put my “I’m creating new stuff” hat on.
  2. Update my svn working copy, to see whether the team changed anything while I wasn’t working.
  3. Commit the team’s changes (if any) to my git repository with a commit comment that describes the svn commit, such as its revision number.
  4. Do a little work.
  5. Commit to my git repository.
  6. Repeat until I’ve completed enough work worth sharing with the team.
  7. Put my “I’m integrating” hat on.
  8. Update my svn working copy, to see whether the team has changed anything while I was working.
  9. Commit the team’s changes (if any) to my git repository with a commit comment that describes the svn commit, such as its revision number.
  10. Commit my changes (as one big change) to the team’s svn repository.
  11. Put my “I’m drinking coffee” hat on.
  12. Drink coffee.

If you’ve worked with git before, you’ll notice that “publish to svn/p4/ClearCase” takes the place of “git push” in the workflow; otherwise, it looks and feels the same.

Now you have all the benefits of committing frequently without disturbing the rest of the team. Even if other people on the team want to do the same thing, don’t share your git repositories; instead, publish to each through the team’s svn/p4/ClearCase repository. You can safely switch to git when everyone wants to switch, and then as a team you can publish your changes to the old svn/p4/ClearCase repository only if someone outside the team (such as the Corporate Standards Czar or the Build Team or the automated build system) requires it.

Most importantly, no special tools required to start—only discipline and practice. You can do that, right?

But Wait! There's More...

In late 2015 I discovered a handy set of shortcuts that make it more convenient to run git from the command line. If you, like me, use oh-my-zsh, then you really ought to take a few minutes to look at its git plugin. I find it much more pleasing to do this:

$ gss #=> git status -s
$ gaa #=> git add -A
$ gss #=> git status -s again, just to be sure
$ gcmsg "We now do this new wonderful thing" #=> git commit -m
$ gp origin && gp production #=> git push...

Reactions