Merge two git repository histories

I want to combine a cvs and a svn repository into a new git repo, without loosing history of course. The catch is the svn repo is a direct continuation of the cvs repo historywise. Someone just created the svn repo and clumsily added the last state from cvs without keeping any history. The most recent sources are in svn. I don’t want to keep the old repos.

The history in graphics:

CVS: A - B - C
SVN: D - E - F - G

What I want:

GIT: A - B - C - D - E - F - G

I made a git repo from cvs with cvs2git, and another git repo from svn with git svn clone as outlined in http://john.albin.net/git/convert-subversion-to-git but just can’t figure out how to combine the two. I did this:

git clone cvs.git
cd cvs
git remote add svn ../../svn.git
git fetch svn

Now what? git merge -s ours svn/master seems to do what I want but does not create a linear history:

A - B - C - - - H'
               /
D - E - F - G /

Any experiments with git rebase didn’t get me anywhere.

  • MySQL Version Control - Subversion
  • Recover SVN password from local cache
  • Can I import from SVN to Git without connecting to a remote server?
  • How often to comment when committing code?
  • What's the difference/connection between the SVN and GIT repos of FreePascal/Lazarus
  • git-svn: Is there a good branching and merging pattern?
  • Anyone use SvnMapper?
  • cherry-picking with git-svn
  • 2 Solutions collect form web for “Merge two git repository histories”

    Use .git/info/grafts to connect histories and then git filter-branch to make it permanent.
    There is a some description how somebody done it: http://bugsquash.blogspot.co.uk/2010/03/stitching-git-histories.html

    Using what kan wrote I came up with this solution:

    git clone cvs.git
    cd cvs
    git remote add svn ../../svn.git
    git fetch svn
    

    Use git log --all to find the unconnected histories:

    ...
    |
    * ab42f52 2011-09-14 06:03:07 +0000 |  [svnuser]
    |
    * 1985b93 2011-09-14 06:00:00 +0000 | Migration from CVS [svnuser]
    
    * 12e0ed4 2011-09-14 05:58:10 +0000 | *** empty log message *** (HEAD, origin/master, origin/HEAD, master) [cvsuser]
    |
    * 5060a7f 2011-04-18 14:07:03 +0000 | *** empty log message *** [cvsuser]
    |
    ...
    

    Find the full SHA1:

    git show 1985b93
    git show 12e0ed4
    

    Create the graft:

    echo 1985b9305ebc819e760f7ecf8e2abe7963eac055 12e0ed4c3dd75cec396a2d228825702eab73ba19 > .git/info/grafts
    

    Now the histories are connected but not yet permanent:

    |
    * ab42f52 2011-09-14 06:03:07 +0000 |  [svnuser]
    |
    * 1985b93 2011-09-14 06:00:00 +0000 | Migration from CVS (grafted) [svnuser]
    |
    * 12e0ed4 2011-09-14 05:58:10 +0000 | *** empty log message *** (HEAD, origin/master, origin/HEAD, master) [cvsuser]
    |
    * 5060a7f 2011-04-18 14:07:03 +0000 | *** empty log message *** [cvsuser]
    |
    

    Make it permanent as shown in http://bugsquash.blogspot.co.uk/2010/03/stitching-git-histories.html:

    git branch svnmaster svn/master
    git filter-branch -- 12e0ed4c3dd75cec396a2d228825702eab73ba19..svnmaster
    

    This creates new commits but also leaves the original svn commits. git log --all will show it:

    * 849278b 2013-04-15 16:31:44 +0000 | Java 6 in Eclipse.  Deployed. (svnmaster) [svnuser]
    |
    ...
    |
    * c33f7cc 2011-09-14 06:03:07 +0000 |  [svnuser]
    |
    * 7acb3ed 2011-09-14 06:00:00 +0000 | Migration from CVS [svnuser]
    |
    | * b3d5413 2013-04-15 16:31:44 +0000 | Java 6 in Eclipse.  Deployed. (svn/master, refs/original/refs/heads/svnmaster) [svnuser]
    | |
    ...
    | |
    | * ab42f52 2011-09-14 06:03:07 +0000 |  [svnuser]
    | |
    | * 1985b93 2011-09-14 06:00:00 +0000 | Migration from CVS (grafted) [svnuser]
    |/
    |
    * 12e0ed4 2011-09-14 05:58:10 +0000 | *** empty log message *** (HEAD, origin/master, origin/HEAD, master) [cvsuser]
    |
    * 5060a7f 2011-04-18 14:07:03 +0000 | *** empty log message *** [cvsuser]
    |
    

    Remove the graft, the duplicate history will be gone:

    rm -r .git/info/grafts .git/refs/original
    

    Clean up:

    git reset --hard svnmaster
    git branch -D svnmaster
    

    And push:

    git push
    

    All done!

    Git Baby is a git and github fan, let's start git clone.