Skip to content

Instantly share code, notes, and snippets.

@crcastle
Forked from dcarney/git-svn notes.txt
Created March 12, 2012 18:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save crcastle/2023790 to your computer and use it in GitHub Desktop.
Save crcastle/2023790 to your computer and use it in GitHub Desktop.
Some hastily-scribbled notes about using git-svn with our existing git repos
Set the SVN_EDITOR var:
# export SVN_EDITOR=vim
==================================
SETTING UP A NEW SVN PROJECT
==================================
Create a new SVN "repo" (aka folder):
(NOTE: https is required for our new SVN, as well as --username)
# svn mkdir https://some/url/path/to/newRepo --username first.last
Ensure that the "repo" is set up with the conventional SVN layout, e.g:
path/to/newRepo
/newRepo/trunk
/newRepo/branches
/newRepo/tags
==============================================
CLONING/WORKING WITH AN EXISTING SVN PROJECT
==============================================
Create a new git repo w/ a remote that points to the SVN location from above:
(The -s or --stdlayout args tell git where to fetch, branch, and tag. You did
use the conventional SVN layout, right??)
# git svn clone -s https://some/url/path/to/newRepo
# cd newRepo
To create a branch in SVN:
# git svn branch -m "Creating a new branch for feature x" feature_x
To create a local branch that tracks the new remote branch:
# git checkout -b local/feature_x feature_x
"Push" to SVN:
# git svn dcommit
To get the latest changes from SVN into the working copy (aka "git pull")
# git svn fetch
# git svn rebase
=================================================
MERGING REMOTE BRANCHES
=================================================
This occurs when we branch from DEV to TEST for instance.
!!UPDATE!!
After spending a bunch of time fixing the remote tracking for several of my
local branches, I've come to the conclusion that rebasing is a "safer" way
to merge branches when using git-svn. This link: http://goo.gl/ZMPfC
was helpful in making the determination. An excerpt:
> git svn dcommit decides which Subversion branch to push to based on the
> most recent svn-id in the history. The git svn documentation explains
> this is done by going back through the history following the first parent
> in each instance:
>
> If you do merge, note the following rule: git svn dcommit will attempt to
> commit on top of the SVN commit named in:
> # git log --grep=^git-svn-id: --first-parent -1
>
> You must therefore ensure that the most recent commit of the branch you want
> to dcommit to is the first parent of the merge. Chaos will ensue otherwise,
> especially if the first parent is an older commit on the same SVN branch.
So, w.r.t merging local branches that each track remote svn branches:
THE NEW WAY:
# git checkout local/branch_to_merge
# git rebase local/brange_to_merge_into
# git checkout local/branch_to_merge_into
# git svn dcommit
THE OLD WAY:
The merge operation is done locally, then pushed to SVN as per usual.
The scenario where SVN is 'branched' via deleting the target dir
and copying the source dir hasn't been tested with git-svn, so
it effects are unknown:
# git checkout local/branched_to_merge_into
# git merge local/branch_to_merge
# git svn dcommit
=================================================
TAGGING
=================================================
'Tag' in SVN: (which is really the same as a 'branch' in SVN, which is really just a 'copy')
# git svn tag v0.1.9
Tag in git:
# git tag v0.1.9
Ideally, these two commands would be done in immediate succession, with no commits
or changes in between. That way, the git tags match up perfectly with the SVN tags.
NOTE: When a new dev clones the SVN repo using 'git svn clone', they'll see these new
SVN 'tags' as branches. This is jsut an unfortunate side-effect of the way that SVN
handles 'tags'. For now, I don't have a workaround.
=================================================
IMPORTING AN EXISTING GIT REPO TO SVN w/ HISTORY
=================================================
To pull in history from an existing git repo:
- Add a remote to the new repo that points to the existing ("old") repo:
# git remote add temp file:///Users/foobar/path/to/old/repo
- fetch from the old:
# git fetch temp
- Checkout your old master:
# git checkout temp/master -b WIP
- Rebase those changes on top of the new repo:
# git rebase master
- Update master to point at your new HEAD:
# git checkout master
# git merge WIP
- Delete the remote and the temporary branch:
# git branch -d WIP
# git remote rm temp
What you are actually doing (from http://goo.gl/If9FA)
Firstly, by adding the remote reference and fetching, you are pulling the commits from your previous repository
which you do not yet have in your current repository. Git knows how to do this because, no matter where or how
it was made, the same commit looks the same everywhere. It is the SHA1 hash of a few well-known pieces of
information, including the directory tree, the committer, timestamp, ...
So when you created a new Git repository based on the same SVN repository, all the commits had the same SHA1 sums.
As a result, the new commits that you fetched into your current repository continued to point at the right stuff.
This is very cool, and important to remember.
You then switched to the tip of temp's master branch and told it to rebase onto your current master. The rebase
may have been unnecessary, as master from SVN may not have moved away from the master in your old repo, but it
was best to be safe.
A rebase finds the nearest point of commonality between two commits by working backwards through their histories
until they both point at the same parent commit. It then switches to the branch name you gave it (in this case
master) and cherry-picks each of the commits that were missing from its history from your original branch. Once
complete, it points the branch you were on when you started at the last commit it applied.
Finally, the merge of master with wip was just to fast-forward master to the end. As it was a straight line, it
really was just a fast-forward. You could have just as easily done a rebase or a reset --hard; any of these would
have altered the master branch to point at the correct location. Merge was just the safest of these, because if
something weird had happened, it would have let you know that it was not a simple fast-forward.
# git svn info
# git svn dcommit --commit-url <some_url> --dry-run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment