Using Git with SVN

I've been using Git with Subversion successfully for months now. I thought I would write up a quick guide on how to use git and svn at the same time without loosing your mind.

A note about differences between git and svn

The main difference between Git and svn is that within a branch, svn has a linear history. I can ask questions like "On this date, what did the files in the repository look like?" All changes occur one right after the other. New changes always are at the newest revision.

In git, all the assumptions above are broken. I routinely have histories that look like this:


 revision 1 --> revision 2a ----------------------> revision 3
            \                                   /
             \--> revision 2b --> revision 2c -/

I know that revision 3 comes before revision 1, but does revision 2c come before 2a? That's not a well-posed question in git. This is what it means for code history to be non-linear.

  • Disadvantage: It makes going back in time tricky, and it complicates display of code history. Git needs gitk in order to view histories.
  • Advantage: If the code isn't ready to compile as of revision 2b, you never see that behavior on the main code line.

Anyway, svn can't handle trees like the above. Git won't let you check in something with a non-linear merge history into an svn repository.

Rebasing versus merging

Assume that Rob is working on revision 2a, and that Gernot is working on 2b and 2c. These changes have to be merged. Git's default behavior is to create a new revision with the contents of both branches, and mark it as a merge:


 revision 1 --> revision 2a ----------------------> revision 3
            \                                   /
             \--> revision 2b --> revision 2c -/

This works, but it produces non-linear histories.

The other way to check in is to remake the tree like so:


 revision 1 --> revision 2a --> revision 2b' --> revision 2c' --> revision 3
            \                                  
             \--> revision 2b --> revision 2c

... where 2b' and 2c' are just copies of 2b and 2c, but adjusted so they have the right parent. It's called a Rebase.

  • Advantages: History becomes linear.
  • Disadvantages: 2b' didn't really come after 2a. If there are merge conflicts, 2b' might be way different from 2b. 2b' also isn't tested. 2b might have compiled, but there is no guarantee that 2b' will compile.

You can think of rebasing as what svn does when you run svn up. If you have local changes in your directory, svn will try and merge those changes so they are based off the most recent revision of the repository. Svn only allows you to rebase one uncommitted revision, whereas git lets you rebase multiple local revisions.

Quick start guide to use git like svn

  • Create a repository from SVN: git svn clone --stdlayout svn://server/directory
    • This copies the whole repository to the main code.
  • Check in locally: git commit -a
  • Create a new local branch: git checkout -b new_branch trunk
  • Update: git svn rebase
  • Check in remotely: git svn dcommit

Git gotchas

  • To revert a file to the last known good revision:
    • git checkout file
  • To switch local branches
    • git checkout branch
  • To add a file to the repository
    • git add file; git commit

Read http://marklodato.github.com/visual-git-guide/index-svg.html for an explanation of why Git works this way.

Neat git tricks

  • To check in only part of a file:
    • git add -p ; git commit
  • To fix a local commit that hasn't gone to svn yet
    • git commit --amend

Sharing git repositories across a machine

Occasionally you may want to take git revisions from machine to machine, without checking into svn and checking back out again. I'm still working on a way to do this sanely. I suggest the following:

  • On a server you have access to everywhere, run git svn clone --bare --stdlayout svn://server/directory
    • The --bare is really important, or bad bad things will happen.
  • To copy this repository, run
    • git clone ssh://server/dir/to/git/repo
  • To update from this repostitory
    • git fetch ; git rebase origin/branch branch
    • Don't use git merge or git pull, as that introduces non-linear history, and you won't be able to commit results back to svn.
  • To push to this repository
    • git push branch:branch
    • If this gives you an error, then update first.
Topic revision: r1 - 01 Mar 2010 - 18:12:23 - RobBlake
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback