Search code examples
gitsvngithubmigrationgit-svn

Apply all commits from one repo to another


Context: My job decided to switch from subversion to git. They have 5 svn repos that need to be converted, 4 of which are small and can be migrated with git-svn in under an hour. The last is much bigger and git-svn runs for days and eventually crashes, so i've been experimenting with other tools like subgit, svn2git, KDE's svn2git, etc. All of them fail at the same point, a revision over a year ago, and crash.

KDE's svn2git has been the fastest and most effective so far, and its rules have allowed me to create two git repos: one with all the commits before the problem, and one with all the commits after. Now i need to correctly merge them into one git repo.

I know how to add one repo as a remote of another and cherry pick the commits over (git: Apply changes introduced by commit in one repo to another repo), but I need a way to do it over the entire repo and all its branches.

How can i apply all of the commits of one repo on top of another?

Edit: I'm looking to do something similar to what git rebase does so that the history is complete and accurate across the entire repository


Solution

  • The awesome guys at Github gave me an answer over email.

    1. Fetch the earlier part of the git history into the Git repository containing the later part of the history:

    $ cd recenthistory $ git fetch ../oldhistory 'refs/*:refs/remotes/oldhistory/*'

    1. For each branch that appears both in the earlier and the later part of the history:

      • Find the oldest commit on the branch in the "recent" history. This should be an orphan commit (i.e., have no parents) so it should appear alone on the last line of the output from this command:

    $ git rev-list --topo-order --parents refs/heads/$BRANCH | tail [...] bf0c6e839c692142784caf07b523cd69442e57a5 e497ea2a9b6c378f01d092c210af20cbee762475 e497ea2a9b6c378f01d092c210af20cbee762475 8bc9a0c769ac1df7820f2dbf8f7b7d64835e3c68 8bc9a0c769ac1df7820f2dbf8f7b7d64835e3c68 e83c5163316f89bfbde7d9ab23ca2e25604af290 e83c5163316f89bfbde7d9ab23ca2e25604af290

    • Create a graft to make it look like this commit actually has the tip of the corresponding branch in the old history as its parent:

    $ echo "e83c5163316f89bfbde7d9ab23ca2e25604af290 $(git rev-parse "refs/remotes/oldhistory/$BRANCH")" >>.git/info/grafts

    1. After you have completed step 2 for all branches in your repository, use git filter-branch to make the grafts permanent:

    $ git filter-branch --tag-name-filter cat -- --branches --tags Verify that the history is correct.

    1. Push the resulting history to your GitHub repository. Please note that if you already have branches or tags in your GitHub repository, this will overwrite them!:

    $ git push origin --force --all $ git push origin --force --tags

    1. Clone a fresh copy from GitHub and double-check that everything is OK.

    2. Delete the recenthistory and oldhistory repositories (perhaps making backups first). The histories in these repositories is not compatible with the history in GitHub, so you want to be sure not to do any further work in them.