2

Background

I am trying to migrate an SVN repository that was formerly 2 svn repositories (but within the same svn server, so sharing commit numbers), which was then combined.

So initial state (two repos):

http://svn/mergeTwoProjectsTest/project1/branches/4.0.0
http://svn/mergeTwoProjectsTest/project2/branches/4.0.0

Combined state (1 repo with folders)

http://svn/mergeTwoProjectsTest/branches/4.0.0/project1
http://svn/mergeTwoProjectsTest/branches/4.0.0/project2

The per repo history ends up looking "interesting" but the per file history is preserved in svn (and svn annotate works perfectly).

When attempting to move this to git using git svn git behaves as if these files were first created at the point the 2 repos were combine and loses any history from before then. This is arguably not unreasonable as this is when those files entered the repository, but in git terminology it is perhaps "two forks that forked when no work had been done, remained separate for several years then merged"

Question

Is it possible to migrate an SVN repository that was once 2 SVN repositories to git while maintaining history from before the 2 svn repositories were merged

Related Questions

My problem looks similar to How can I clone an svn repository that changed layouts with git maintaining full history? however my case seems worse, as I have 2 competing repos being combined, rather than just a structure change.

3
  • Why not just do a git merge <remote> <branch> --allow-unrelated-histories? See: git-scm.com/docs/git-merge#Documentation/… for more info. It's not the cleanest approach, but it does do the trick and might be less risky from the standpoint of losing history. The merge will be ugly, but it will be a traditional merge. Oct 16, 2020 at 19:44
  • @Greg is that an addendum to sevensevens suggestion; ie. do it in several parts. Just want to make sure theres not something I can do to take the entire SVN history (which included unrelated history merges) in one shot as part of the git svn clone command Oct 19, 2020 at 8:18
  • Unfortunately there is no magic here. The Git SVN clone is its own history. You can commit to it, and sync it with SVN, but if your intention is to just move to Git, then to the ugly merge once with --allow-unrelated-histories and wade through the conflicts. This should be a one time thing if the files and directory structure are the same. File renames in either version control will be ugly conflicts, but other than that resolving conflicts shouldn't be too bad. Oct 19, 2020 at 11:15

2 Answers 2

3

Is it possible to migrate an SVN repository that was once 2 SVN repositories to git while maintaining history from before the 2 svn repositories were merged

Assuming you still have the 2 svn repositories you can git svn clone them into 2 separate git branches and then merge them in git.

This would completely preserve history as you've always got the original branches. You'll have a 3rd branch with the merge.

git svn clone works by checking out each svn commit in order and then creating a matching git commit. The history should be the same as whatever repo you've cloned between svn and git. If you already foo-barred the merge in svn and don't have the original repo, you might be stuck, but that's svn's fault, not git's.

3
  • 2
    Would that mean losing the history since the svn repository merge though? Oct 16, 2020 at 16:52
  • Interesting, with careful selection of the revision numbers to bring it in this could work as a git svn in 3 parts Oct 16, 2020 at 17:57
  • This helped a lot +1, but I also needed git filter-repo and git replace --graft to make it all work. I detailed that in my own answer Nov 25, 2020 at 18:19
1

Sevenseven's answer was an extremely good starting point, but I needed a few extra steps to get the full solution.

Get the pre merge history in Git (as a number of separate git repositories)

As in SVN they were separate repositories in SVN at that time it makes sense for them to be similarly in git

Determine the SVN revision that occurred just before the SVN repositories were merged (for the example we'll assume pre rearrange history of 1-100, rearranged at 101-105, post rearrange from 106

For each of the original svn repositories pull their changes

git svn clone http://svn/mergeTwoProjectsTest/project1 C:\projects\GitConversion/project1 --stdlayout --revision 1:100
git svn clone http://svn/mergeTwoProjectsTest/project2 C:\projects\GitConversion/project2 --stdlayout --revision 1:100

The folders will be empty this is fine. The import takes AGES and the next step is destructive, so I suggest taking a backup of these repos.

Add a subfolder to mirror what happen in SVN

When the histories of these are rearranged from 2 repos to 1 they will be within a subfolder in the single rearranged repo. So this subfolder can be added using filter-repo. This isn't part of core git and must be installed.

Open a command prompt within each of these repos and run the following command in each

git filter-repo --to-subdirectory-filter [SUB_PROJECT_NAME] --force

In my example [SUB_PROJECT_NAME] would be project1 in the first repo then project2 in the second repo. The important thing is to mirror whatever happened in SVN

Smoosh the repos together

In git terminology what you are doing is merging forks with unrelated history, in SVN you were rearranging several separate repositories into just one big one.

Next create a new (third) repository, name it whatever your overall project is called followed by _preRearrange, I will call it overProject_preRearrange in this example.

Within overProject_preRearrange open a command prompt and add the 2 sub project repositories as remotes

git remote add [NAME_OF_SUB_PROJECT] [PATH_TO_SUBPROJECT]
git fetch [NAME_OF_SUB_PROJECT] --tags

For each branch check it out

git checkout -b [BRANCH_NAME] master

And then merge its composite parts into it

git merge --allow-unrelated-histories [SUB_PROJECT_NAME]/[BRANCH_NAME]

e.g.

git merge --allow-unrelated-histories project1/4.0.0
git merge --allow-unrelated-histories project2/4.0.0

At this point the term "preRearrange" may seem incorrect. But they contain the history of all the commits which happened preRearrange, even if the merging of the forks has happened

Get the post merge history in Git

This will be a shallow history, appearing to begin at the point the rearrangement happened, don't worry about that.

Pull the post rearrangement history from SVN

git svn clone http://svn/mergeTwoProjectsTest C:\projects\GitConversion\overProject_postRearrange --stdlayout

Graft the gap

By grafting these 2 repositories together you will get a continuous (if unusual) history.

Open a cmd window in the preRearrangement

Add the postRearrangement repository as a remote

git remote add postRearrangement [PATH_TO_POST_REARRANGEMENT]
git fetch postRearrangement 

For each branch you want to stitch together (any that have changed since the rearrangement) determine the first commit in postRearrange after the rearrange was fully complete in that branch (i.e. the first normal commit). And the last commit in preRearrange (this will be one of our merges)

git checkout [BRANCH_TO_GRAFT]
git replace --graft [FIRST_NORMAL_COMMIT_IN_POST_REARRANGE] [LAST_COMMIT_IN_PRE_REARRANGE]
git merge postRearrangement/[BRANCH_TO_GRAFT]

e.g.

git checkout 4.0.0
git replace --graft f5581bf6706fabd442253ae3c8fb2a974a74170e d60e9d4faa3f7d2fab3d4314df4fc27d7e50d90a
git merge postRearrangement/4.0.0

The preRearrange repo is the one you want to ultimately keep.

Check its all good

At the end of this process you should have a continuous history (and a lot more git experience), you may want to do some sanity checking before declaring yourself done.

Look at the history of your grafted branches, they should look like this:

enter image description here

Equally you may wish to do a git blame on a file that was edited both before and after the rearrangement, it should show lines edited both before and after it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.