descriptionDetect SVN merges from their commit messages and re-create the merges in the Git side.
homepage URL
last changeTue, 22 Jan 2008 12:53:57 +0000 (22 13:53 +0100)
content tags

This script can be used to import merges you've done on the SVN side to the Git side. It's especially useful when you're in process of converting a SVN repo to Git and you want to recreate a history similar to that of SVN. Alas, SVN does not record merges in any way so it's far from trivial to recover them on the Git side. This script assumes that you have been well behaved and that you always mentionned which revisions from which branch were merged. It uses one RE (RegExp) to match these commits from their commit messages (possibly excluding false positives with other REs) and then rewrites the entire history of your repo to add the merges detected in Git. Obviously, this requires that you've always formatted your merge commit messages in a similar way, but in practice this is common. Indeed, people often use scripts to diminish the pain of the famous "SVN merge hell". These scripts tend to record metadata as to what has been merged when. And they often generate the commit message which contains which revisions are being merged from which branch.

Full SVN to Git conversion, step by step:

  1. git svn clone -s repo
  2. Repack: git gc --prune --aggressive
  3. Rename all the remote SVN branches to local Git branches:
         cd .git
         mv refs/remotes/tags/* refs/tags/
         mv refs/remotes/* refs/heads/
         sed -i 's|refs/remotes/tags/|refs/tags/|;s|refs/remotes/|refs/heads/|' packed-refs
  4. Optionnaly: Rename the `trunk' branch to `master' Make sure that git-svn created the `master' branch correctly. Normally it should initialize it to SVN's `trunk' but I've seen cases where it does not. Then issue git branch -d trunk
  5. Convert SVN merges to Git merges: --all --verbose --prune. You might need to tweak the first few variables ($merge_pattern, $exclude_pattern and $log_exclude_pattern). If the script could not find the parent of some merge commits, it will print them before re-writing the entire history and ask you whether it should continue or not. I suggest you tell it not to continue and have a look at each of the problematic commit and then invoke the script again with the proper --merge arguments to manually indicate the merge points. For instance, if the script complains that it couldn't figure out the parent of the merge commit f309a61, look at this commit with git show and note down the SVN revision and branch that are being merged by this commit and re-invoke the script with --merge f309a61:51:branches/1.0 (if you found out that commit f309a61 was merging -r42:51 from the branch 1.0)
  6. Get ready to re-distribute the repo:
         git config core.bare true
         git config core.sharedRepository true # Use this if needed (e.g. you use gitosis)
         rm -f .git/{index,gitk*,qgit*,*_HEAD,BISECT_*,COMMIT_*}
         mv .git ../repo.git
         cd ..
         rm -rf repo
         cd repo.git
         sed '/refs\/remotes/d' -i packed-refs
         rm -rf refs/remotes/origin
         git reflog expire --expire=0 --all
         git gc --prune
  7. Now you're ready to distribute repo.git!

Send {comments,suggestions,bugs,feature requests,patches} to <tsuna at lrde dot epita dot fr>
2008-01-22 Benoit SigoureCouple of minor fixes.master
2008-01-21 Benoit SigoureDo not process the same commit more than once.
2008-01-21 Benoit SigoureHandle user-specified merges and exclusions.
2008-01-21 Benoit SigoureMore warnings.
2008-01-21 Benoit SigoureFix a couple of bugs.
2008-01-21 Benoit SigoureAdd more options.
2008-01-20 Benoit SigoureFind the merge parent faster.
2008-01-18 Benoit SigoureFix the way merge points are computed.
2008-01-18 Benoit SigoureInitial version.
9 years ago master