Version 2

    If you're using Git SVN as your local SVN client, you no doubt understand the benefits of having multiple local branches. Well, you can also use this same local Git repository to help you work with multiple SVN branches, too.  This article shows you how to create branches in your Git repository that mirror the remote branches, and describes a simple workflow for applying changes to multiple branches.

     

    Setup

    Your local Git repository will already know about any SVN branches and tags that existed when you created your Git repository by cloning SVN. But it may not know about any more recent branches. So the first thing is to tell your local git repository about the new branch in SVN. For example purposes, we'll assume we're going to work on the '2.2.x' branch.

     

    These two commands add information to your local '.git/config' file:

     

    $ git config --add svn-remote.2.2.x.url https://svn.jboss.org/repos/modeshape/branches/2.2.x/

    $ git config --add svn-remote.2.2.x.fetch :refs/remotes/2.2.x

     

    The bold '2.2.x' is the local name for the branch. Next, fetch all of the history for the branch (this may take a bit, though there is not a lot of commits on this branch):

     

    $ git svn fetch 2.2.x

     

    You need a local branch that you can work with, so create one called 'local-2.2.x' that is tied directly to the remote '2.2.x' branch:

     

    $ git checkout -b local-2.2.x -t 2.2.x

     

    Check that your local git config file looks right. The relevant lines are shown below:

     

    $ more .git/config

    ...

    [svn-remote "2.2.x"]

    url = https://svn.jboss.org/repos/modeshape/branches/2.2.x/

    fetch = :refs/remotes/2.2.x

    [branch "local-2.2.x"]

    remote = .

    merge = refs/remotes/2.2.x

    ...

     

    Check that the branches are defined correctly by listing all branches. The output should include the '2.2.x' remote branch (in red), plus the 'local-2.2.x' local branch:

     

    $ git branch -a

    ...

    local-2.2.x

    ...

    2.2.x

    ...

     

     

    Developing on the branch

    I generally develop on topic branches, commit locally, merge to 'master' (trunk), and dcommit (push to SVN trunk).  Here's my basic workflow:

     

    $ git checkout -b mode-903


    # ...  lots of changes ...


    $ git commit -m "MODE-903 ..."

    $ git checkout master

    $ git svn rebase

     

    If there are changes, you need to rebase first. The following command will check out the 'mode-903' branch and do a 'git rebase master', leaving you on the 'mode-903 branch'. The second command takes you back to your master branch:

     

    $ git rebase master mode-903

    $ git checkout master

     

    Now, your 'mode-903' topic branch is updated with the latest from SVN and includes your (locally committed) changes, so merge those changes onto master and push them to SVN:

     

    $ git merge mode-903

    $ git svn dcommit

    Committing to https://svn.jboss.org/repos/modeshape/trunk ...

    M docs/reference/src/main/docbook/en-US/content/jcr/web_access.xml

    Committed r2304

    M docs/reference/src/main/docbook/en-US/content/jcr/web_access.xml

    r2304 = f08cf380179691e195bf3f2dfb16aecb4f8c00ee (trunk)

    No changes between current HEAD and refs/remotes/trunk

    Resetting to the latest refs/remotes/trunk

     

    Until this point, the workflow is just working on 'master' (trunk). If you want to take those same changes and apply them to the '2.2.x' branch in SVN, you need to do that next.

     

    The workflow is easy: switch to the 'local-2.2.x' branch, get the latest from SVN, and apply the same changes you made on 'master' onto the current (e.g., '2.2.x') branch. This is called cherry-picking in Git terminology. This is basically a shortcut for creating a patch file for a commit, applying that patch file to the other branch, and staging the changes locally. You can do this so easily because Git allows you to reference a commit by its reference (e.g., "f08cf3801"), which is just enough of the SHA-1 of the commit that is unique.  Here are the commands.

     

    First, switch to the local-2.2.x branch:

     

    $ git checkout local-2.2.x

    Switched to branch "local-2.2.x"

     

    Then, perform the cherry-pick.


    $ git cherry-pick f08cf3801 -n

    Finished one cherry-pick.

     

    The '-n' flag tells Git that you don't want the changes automatically committed with the same commit message. You'd actually like to do that, except that Git SVN includes the SVN URL in the commit message, so a message for a commit against 'trunk' will be a little wrong if it's used as the message for a commit against another branch.  Using the '-n' flag gets around that.

     

    You now have in your staging area the changes from the referenced commit, and you simply need to commit them and push them to the '2.2.x' branch in SVN. You could retype your commit, but if you have history setup, you can just re-run the appropriate 'git commit ' command.

     

    $ history 30

    # find the command in the output; let's say it's command 1234

    $ !1234

     

    Or you can just type out the commit again:

     

    $  git commit -m "MODE-903 ..."

     

    Now that you've committed locally, you can push the commit to SVN by doing a normal 'dcommit'.

     

    $ git svn dcommit

     

    Applying multiple commits to a branch

    Sometimes, you might create multiple commits on your topic branch, merge those onto 'master', and push them to SVN's trunk. Cherry-picking these onto your local '2.2.x' branch is easy: just use a cherry-pick and local commit command for each of the commits you want to cherry pick. Then, you have multiple local commits on the '2.2.x' branch, and a single 'dcommit' will push them all into SVN.