Current Articles | RSS Feed
So, you're interested in trying out Git – or you've even tried it for your own private projects and liked it – but at work, the existing repositories all use Subversion. Maybe you plan to switch over to Git, but you want a commitment-free tryout before you take the plunge and switch wholesale. Fear not: git-svn is here to help you.
git-svn is a neat, straightforward tool that allows you to run a Git repository locally, then sync back against a central Subversion repository. Obviously, this is useful if you want to try Git out, or if your workmates aren't interested in switching but you prefer Git. But it's also handy for anyone who regularly works offline – for example, when traveling. Git, unlike SVN, is a distributed version control system, which means that you have your own local copy of the repository. This, combined with the ease of branching (which we'll talk about in a moment), means that you can keep track of your changes locally and incrementally, committing them to your own repository as often as you like, until you're ready to commit the whole lot back to the main repository. By contrast, with a normal Subversion repository, it's all or nothing; you can't track any incremental changes that you can't or don't want to commit to the main repository – as you might wish to do, for example, with temporarily broken code on its way to a refactor. If you've ever got halfway through coding a feature change and started to feel nervous about how much you have untracked, you'll appreciate this option. For more on Git's advantages in this area, see the Wazi article Rewriting History with Git.
git-svn is available as a package for CentOS and most other Linux distros, or as a port for Mac OS X. You can get it for Windows via Cygwin or mysysgit. Once you've installed it, you can check out a Subversion repository with a command like git-svn clone --stdlayout http://example.com/svn_repo myrepodir. The --stdlayout option tells git-svn that your Subversion repository has a standard layout (trunk/, branches/, and tags/). If that's not true, leave it off; you can instead use -T trunk -b branches -t tags to specify the parts of your Subversion setup.
git-svn clone --stdlayout http://example.com/svn_repo myrepodir
--stdlayout
git-svn
-T trunk -b branches -t tags
This command generates a Git repository in myrepodir/ that matches the Subversion repository. However, note that git-svn doesn't copy empty directories or files, because Git tracks the contents of files and directories rather than the files themselves.
Cloning a repository from Subversion doesn't import the repository's "ignore" settings – that is, the files and folders in your source code tree that you don't want to include in the repository. You need to set up ignores manually. Run the command git-svn show-ignore > .gitignore to generate a file that you can commit back to the Subversion repository. Other developers who are also using git-svn can use the same file without having to run the (somewhat sluggish) command again.
git-svn show-ignore > .gitignore
Once you've created your local repository, you interact with it as you would with any Git repository. You'll only need git-svn again when the time comes to commit back to the central Subversion repository. The basic Git commands should look pretty familiar:
git add newfile
git rm oldfile
git rm -r olddir
git commit
git commit only commits changes that you have explicitly added with git add. To commit all changes without adding them first, use git commit -a, which commits all changes to all files since the last commit.
git add
git commit -a
Git also offers interactive adding. git add -i shows you all the files that currently have changes. Press "u" to update files, then enter the numbers of the files you wish to update and press Enter. Type "status" to see the change in the file status. Quit, then run git commit to commit the changes.
git add -i
After you've finished making changes, and before you commit back to Subversion, you need to update your local repository against the remote Subversion repository with the command git-svn rebase. This saves your local changes, downloads and applies all changes from the main repository, then reapplies your local changes on top. Any uncommitted changes will be lost – but you can work around that problem by using git-stash, as we'll see in a moment. Once you've checked that all is still well, run git-svn dcommit to commit back to the central Subversion repository.
git-svn rebase
git-svn dcommit
One of the big advantages of Git is that code branches are lightweight and easy to create, merge, and destroy, allowing you to have multiple versions of the code evolving separately. As a rule, you'll likely want to create a new branch for each new bugfix or feature development you're working on, using a command like git checkout -b branch_featureA. This command creates the new branch branch_featureA off the master branch, then moves you into it. Use git branch to show all the branches of your local repository, and git branch -a to see both local (Git) and remote (Subversion) branches.
git checkout -b branch_featureA
git branch
git branch -a
You can use a remote branch in much the same way. This command checks out the branch svnbranch:
git checkout -b svnbranch-svn remotes/svnbranch
Use the -svn suffix to avoid reference ambiguity warnings. To update this branch, run
-svn
git checkout svnbranch-svn; git-svn rebase
Make sure you don't merge these branches with any others, as they need to remain a clean copy of the upstream Subversion branch. Otherwise when you try to commit back to the main repository, you'll have to untangle your changes back to apply them to the relevant branches, or risk committing, say, v2.0 code to the v1.3 branch. (You can however create new Git branches off from a remote branch, then use one of the techniques below to merge them back into that remote branch, by substituting the name of the remote branch for "master" below.)
You need to be careful when merging a branch back in again, as Subversion doesn't handle merges the same way Git does. To merge a branch in again when using git-svn instead of git merge, you need to commit your changes, then use:
git merge
git checkout branch_featureAgit rebase master
You now have a branch whose code corresponds to "master" (Git's name for the main branch, which in this case matches the Subversion repository) plus your changes. But it's still labeled branch_featureA, so you can't yet commit your changes back to the Subversion repository, as it won't know what to do with them. Instead, tell git to do a forced rename of this branch to turn it back into "master":
git branch -M master
This destroys your development branch (so do it only once you've finished making changes), but you can always rebranch and repeat the whole process. Now you can commit your changes to the Subversion repository with the command git-svn dcommit.
An alternative option is to use the --squash option to git-merge:
--squash
git-merge
git checkout mastergit merge --squash branch_featureA
This switches back to the master branch, then merges all the changes from branch_featureA as a single commit on the master branch. However, this has the major downside of losing the history of all your commits, at least from the point of view of the master branch and thus of the Subversion repository when you commit to it. Rebasing is a better technique in most circumstances.
git stash
git stash is designed for those moments when you want to shuffle changes off your existing tree, but you don't want to lose them (so you don't want to just revert to the previous commit), or to switch to another branch. The stash is effectively a stack of saved changesets, from which you can reapply a changeset at any time.
Use git stash save "work on project foo" to save all your changes to the "stash" and return the project to its state at the last commit. Make your minor fix as usual and commit it, then use git stash pop to put your saved changes back in. If you have multiple changes stashed, you can see them all with git stash list, then apply them individually with git stash apply stash@{1} (the list will give the correct IDs). Note that if you don't save a tag (such as "work on project foo") with your stash, you won't be able to identify it!
git stash save "work on project foo"
git stash pop
git stash list
git stash apply stash@{1}
If you've followed along so far, you've learned all the basics you need to know to get started using Git alongside Subversion. git-svn is a great way to (nearly) seamlessly use Git while your colleagues are still stuck on Subversion. As this little tutorial shows, you can have the best of both worlds.
Allowed tags: <a> link, <b> bold, <i> italics