Using Git with SVN
Author: John Reese
Author’s Note! This tutorial assumes that you are working from a Linux or Unix-like environment, and that you have a general understanding of version control concepts. If you are working from Windows, you will currently need to install Cygwin or a virtual machine with a Linux or Unix-like operating system, as there is no official or stable Git client yet available for Windows.
- access the Mantis repository
- maintain a local mirror of the entire Subversion tree
- branch and commit changes in a local environment without affecting the Subversion tree
- share branches and changes between other developers using Git
- push committed changes back to the official repository
By using Git, you will have the freedom to work on your local mirror of the repository, make changes to it at will (even if you don’t have commit access to the real repository), and easily share your changes for others to use or work from.Getting Started Learning Git
It is highly recommended that anyone interested in Git (who has previous experience with version control software) watch this presentation by Randal Schwartz, "What Git Is". It introduces the concepts underlying Git and how it works. If you are new to version control in general, or if you would prefer to read more about Git, you should check out the Git Crash Course index.Installation
In order to access a Subverson repository with Git, you will need to install Git and the
git-svn tool. If you download and compile the Git tarball directly from the Git website,
git-svn will be compiled along with the core application. Directions for building can be found in the tarball contents, and will not be discussed here.
Most Linux distributions, however, keep
git-svn in a separate package from the primary application. For Debian- or Ubuntu-based linux distributions, the following command will install Git and
For Fedora-based distributions, the following command should be used:$ sudo yum install git-core git-svn
Note: Red Hat Enterprise Linux (and clones like CentOS) does not have those packages in the default repositories, but they can be easily found in third party ones.
A (incomplete) list follows (please pick only one, as mixing repositories is known to be dangerous):Configuration
Once you’ve installed Git and
git-svn, check your installation by configuring your account with Git.
$ git config --global user.email "<Your Email Address>"
This will set the name and email associate with commits in Git. This is important because you want you changes actually attributable to yourself, unless you like being anonymous.
If you are using a terminal that supports colors (you most likely are), then you can configure Git to show colors for different commands, which makes some things easier to read and visualize:$ git config --global color.branch "auto"
$ git config --global color.diff "auto"
$ git config --global color.status "auto"
Then, if you are used to CVS/SVN commands, you may want to set some aliases:$ git config --global alias.ci commit
$ git config --global alias.co checkoutChecking Out
Author’s Note: You will generally need about 300 megabytes of free space during the process, but when you’ve finished this process, the repository should take up less than 40 megabytes.
Now you’re ready to mirror the Mantis Subversion tree to a local, isolated working area. Starting from our home directory, we’ll create a
workspace directory, and then ‘clone’ the the relevant (1.0.0, 1.1.0, and 1.2.0) portions of the Subversion tree into a fresh Git repository:
$ cd workspace
$ git-svn clone https://mantisbt.svn.sourceforge.net/svnroot/mantisbt \
--trunk=trunk/mantisbt --tags=tags \
--branches=branches --revision 4152:HEAD
Note: If you are using cygwin and you get an error relating to Error.pm, see this blog entry for the solution. If you are using Fedora 8 and you get an error relating to Error.pm, “sudu yum install perl-Error”. This is caused by a known bug.
Note: If you are using cygwin and you get the following error: “fatal error - unable to remap C:\cygwin\..... to same address as parent(0×1030000)”, see Unable to remap - Basically close cygwin console window, run “ash” from the cygwin bin folder, and run “/bin/rebaseall” in the opened console window.
At this point, Git will begin communicating with the Subversion server, fetching individual revisions one-by-one and storing them in its local repository. This will likely take a long time, as there are about 800 revisions to fetch at the time of writing. Either work on something else in the meantime, or enjoy watching revision info fly up the screen as Git does its job.
It’s done now? Great! We may have a mirrored repository now, but we’re not done yet. We need to normalize our repository, set up a couple basic branches, and then ‘garbage collect’ to reduce the size of our workspace.
First, we’ll need to make sure our branches are set up right. We’ll do this with the
git-branch command, which we use for both looking at and selecting available branches. The first command will show local branches, and there should be only one, ‘master’. The second command will show ‘remote’ branches from the Subversion server, including tags, and this should show all of them. If this does not show any remote branches, something went foul, and you will need to start form scratch.
$ git branch -r
Now, the ‘master’ branch will already be selected, and we can confirm this by running:$ git status
However, because of the way
git-svn works, the ‘master’ branch may be following different remote branches based on the latest remote commits, so let’s set up some better named branches that we can use. We’ll start by simultaneously creating and checking out a local ‘trunk’ branch that will follow the remote ‘trunk’ branch:
Now, we’ll create (but not checkout) local branches following important remote branches (currently the 1.1.0 branch):$ git branch local-branch_1_1_0 BRANCH_1_1_0
And we no longer need the ‘master’ branch, so we’ll get rid of that to reduce confusion and disk-usage:$ git branch -D master
Finally, we’ve got our branches set up, so it’s time to run ‘garbage collection’ on our repository, so Git will compact or remove unneeded files:$ git gc
And that’s it! Your Git repository is now a local mirror of the Mantis SVN repository. You’ve set up your branches, and you’ve compacted your repo to better utilize disk space. In the next section, we’ll discuss how to maintain your local mirror: how to fetch updates from SVN, merge or ‘rebase’ your changes onto those updates, and send local changes back to the server. Later, we’ll discuss how to share local changes with other developers without committing to the server, and some best practices for using Git.Git-SVN Workflow
Author’s Note: this section assumes that you have learned your way around Git and have already started making some changes.Update From Server
When revisions have been committed to the Mantis SVN server, your local Git repository will need to be told to look for and retrieve those changes:$ git-svn fetch
However, this will only update the repository’s knowledge of the remote branches. You local branches will not be affected, and you will need to specify how you want those changes to be replicated in your local branches. You actually have two options with Git, unlike most other source control tools that only offer a straight ‘merge’.Rebase
This is the preferred method for integrating remote changes into your local branch. Git will take your locally-unique changes, and ‘replay’ them onto a fully-updated version of the branch. This creates a much nicer, linear history, as compared to a ‘merge’.
If you are working on a local branch that directly follows a remote branch, you will need to:$ git-svn rebase
Otherwise, on a branch following another local branch, you will use the generic version:$ git rebase
Conflicts may occur if a remote change is very near, or on the same line as, your changes. If this happens, Git will let you know what files are in conflict (also seen by
git-status after the failed rebase). You will need to manually edit the files to find and resolve the conflicts, and remove the extra symbols/lines pointing out the conflict. After you have saved the resolved file(s), you will need to tell Git that you have resolved the files, and to continue the rebase:
$ git-svn rebase --continue
$ git rebase --continue
If there are too many conflicts, and you want to go back to where you were:$ git rebase --abortMerge
If a ‘rebase’ doesn’t work out, or if you only want to integrate specific changes form one branch to another, you will need to use the ‘merge’ technique. Instead of creating a single, linear history, ‘merge’ will create a more varied, but more flexible history, preserving timestamps. This is generally only recommended for use between two local branches for local changes only.Commit to Server
Author’s Note: This section assumes you have been granted commit access to the Mantis SVN repository. If you do not have commit access, then you may be interested in Sharing Branches with other developers, or Getting your Patches into Mantis.
Once you have committed changes to a local branch, you will need to take further steps to transfer those changes to the actual Subversion server. This process is mostly automated, but the difficulties arise from getting your changes in the right place and the right frame before letting the automation take over.
For the purpose of conveying the ideas of this topic, this section will assume you have three local branches in your Git repository:
local-trunk which follows the remote branch
bug-fix, both of which follow the aforementioned
local-trunk branch. For the sake of simplicity, this section will assume that both branches have independent changes with no major conflicts, and the entire changesets from both branches are to be committed to the SVN server.
The first order of business when pushing changes to the server is to prepare your local branches. This is crucial in making sure that your changes will not break either the working tree on the server or your local repository.
We will start by updating our local repository with the latest changes from the server. This is covered in full in the section above, but we will cover the commands to run here to reinforce the concept. If there are any merge conflicts during this process, you will need to resolve them before continuing further.
First we’ll update
local-trunk which is following the remote branch
$ git-svn rebase
Now we’ll make sure the latest changes are in both of our local working branches,
$ git rebase local-trunk
$ git checkout new-feature
$ git rebase local-trunk
All three branches should now be up to date and ready for the next step; you can verify this by running
git-log on any of the branches and checking to make sure that the latest SVN commits are in the branch history.
Now we will begin merging our changes from the
bug-fix branches into the
local-trunk branch, and double check everything before we start committing the changes to the server.
There are multiple ways to merge everything, which you can read about in the Git manpages and elsewhere online, but for the sake of both simplifying the process and reducing the number of upstream commits, we will squash our local branch merges into single revisions in
First, we will merge the changes from the
bug-fix branch and commit them to
local-trunk as a single revision:
$ git merge --squash --no-commit bug-fix
$ git commit -a
Now we’ll update the
new-feature tree and merge it in the same way as before:
$ git rebase local-trunk
$ git checkout local-trunk
$ git merge --squash --no-commit new-feature
$ git commit -aCommitting the Changes
Now that our
local-trunk branch has the necessary revisions merged from our local branches, we’re ready to push our changes back to the SVN server:
Our code has now been committed to the SVN server, and our Git repo has been updated to have the appropriate revisions in
local-trunk marked with the SVN revisions. If we want, we can continue working from the local
bug-fix branches (after rebasing both, of course), or we can move on to the next session to clean up our repository.
Assuming that work in the
bug-fix branches is now completed, we can delete these branches from our local repo, to keep it cleaner and use less space:
$ git branch -D bug-fix
$ git branch -D new-featureShare Branches Misc. Notes
- To commit from git to svn, use the following command:
Note: If you get a Perl error about Term/ReadKey.pm not found, you can use the following commands on Fedora:su (to run the following commands as super user)
yum install perl-TermReadKey
- To generate a patch with all accumulative changes made on a branch (i.e. changes already committed to the branch):