Migrating SVN to Git with Branches
In my previous post I did a simple migration of a Subversion project to Git. I didn't want to keep any branches or history so purposely got rid of the history - it was more of a copy than a proper migration. This time I will show you how to pull across some branches, and check that your commit history survives.
Instead of starting with an export of the SVN project, we can use a Git tool designed for Subversion. Run this command to tell Git where your SVN repo is, and a little about its structure:
My repository had slightly odd names for the branches and tags folders so I had to use the --b and --t flags tell Git what where to look. Next you can associate any Subversion accounts with the new Git logins. To do this, create an authors.txt file, formatted like this:
with your SVN usernames and the Git user's name and email address in place as appropriate. You can get the full list of Subversion users from the server's authentication files. If you don't have access to the server you can dump all the committers from the history, using:
or
These commands must be run back in your Subversion directory. Once you've put all of these usernames into your authors file and set the Git details, you can apply those logins to Git:
Now to bring across the code.
The git svn fetch command pulls down the code, including any branches and commit history associated with the files. You can check this out by running git log on one of the files:
and by looking at all of the branches available to you:
As you can see, I have a couple of branches containing important features but one branch that I don't want to bring across. I'm going to turn these Feature branches into Development branches in my Git repository, so I can work on them and eventually check them in.
The reason I'm not calling them "feature" branches is that I want to use Git Flow in future (follow the link for the best explanation I have ever seen) and this assigns a special meaning to the feature branch. I don't want conflicts later on, so I've decided that these SVN branches will become "dev" branches.
Once you've linked all the branches you need you can share your repository with the rest of your team. I covered creating a remote repo in Visual Studio Team Services in the previous post, and of course you can use a different hosted Git repo such as BitBucket or GitHub if you want to. Once you have created your remote, link it using:
You'll see I got an error - my master branch and the origin's are different because I told VSTS to add a .gitignore file for me and it committed that as a first change. This means that my remote and local repositories have different commit trees. Fortunately we can merge them together using:
All your branches have been saved on the remote repo now, and you can check them out via the VSTS user interface.
Instead of starting with an export of the SVN project, we can use a Git tool designed for Subversion. Run this command to tell Git where your SVN repo is, and a little about its structure:
git svn init http://svn.example.com/subversion/Project ↩ --prefix svn/ -T trunk --b=branch --t=tag Initialized empty Git repository in C:/tmp/Project/.git/
svn_username = Git User <git@fantail.io> svn_user2 = Git User 2 <git2@fantail.io> ...
with your SVN usernames and the Git user's name and email address in place as appropriate. You can get the full list of Subversion users from the server's authentication files. If you don't have access to the server you can dump all the committers from the history, using:
svn log -q | %{ $_.Split('|')[1]; } | sort-object -unique
or
svn log -q | grep r.* | awk -F\| -- '{ print $2 }' | uniq
These commands must be run back in your Subversion directory. Once you've put all of these usernames into your authors file and set the Git details, you can apply those logins to Git:
git config svn.authorsfile authors.txt
Now to bring across the code.
git svn fetch r5 = 9ebfdd9fd56b512e1a7f7560099048ca2d2bae1a (refs/remotes/svn/trunk) A src/BranchExample.java r7 = 026d475e8659205bd85425bbf824b5e0c2cd058e (refs/remotes/svn/trunk) r8 = 65b946dcc045613270f412a5de60988fc3d28aa4 (refs/remotes/svn/trunk) Found possible branch point: http://svn.example.com/subversion/Project/trunk => http://svn.example.com/subversion/Project/branch/Feature1, 8 Found branch parent: (refs/remotes/svn/Feature1) 65b946dcc045613270f412a5de60988fc3d28aa4 Following parent with do_switch Successfully followed parent r9 = 1905234195364335c44aa23349f0de9a3876206e (refs/remotes/svn/Feature1) Found possible branch point: http://svn.example.com/subversion/Project/trunk => http://svn.example.com/subversion/Project/branch/Feature2, 9 Found branch parent: (refs/remotes/svn/Feature2) 65b946dcc045613270f412a5de60988fc3d28aa4 Following parent with do_switch Successfully followed parent r10 = 3c4d13c82e946524ff3cf4949d92db6077db2d1a (refs/remotes/svn/Feature2) M src/BranchExample.java A src/Feature2.java r11 = 6c9ca531c74a4b9537b5691dae4dd4cc56659f50 (refs/remotes/svn/Feature2) M src/BranchExample.java r12 = 7c9a8ef5f5f79b15d510734d0c428f069aec12d8 (refs/remotes/svn/trunk) Found possible branch point: http://svn.example.com/subversion/Project/trunk => http://svn.example.com/subversion/Project/branch/Feature3, 12 Found branch parent: (refs/remotes/svn/Feature3) 7c9a8ef5f5f79b15d510734d0c428f069aec12d8 Following parent with do_switch Successfully followed parent r13 = 6ed0cd2ce5a9220eb681ce29ebd00d1e6d7b0e7e (refs/remotes/svn/Feature3) M src/BranchExample.java A src/Feature3.java r14 = 56344f2e3d8941c1748912f2f5f28bb109975fbd (refs/remotes/svn/Feature3) M src/BranchExample.java r15 = 1fab22054768c056c7d3317aed495bf3e77b0116 (refs/remotes/svn/Feature1) M src/BranchExample.java A src/Feature1.java r16 = 855456ab9817e173bd014d47a26a94e6d5cd5a85 (refs/remotes/svn/Feature1) Found possible branch point: http://svn.example.com/subversion/Project/trunk => http://svn.example.com/subversion/Project/branch/UnwantedFeature, 16 Found branch parent: (refs/remotes/svn/UnwantedFeature) 7c9a8ef5f5f79b15d510734d0c428f069aec12d8 Following parent with do_switch Successfully followed parent r17 = d554f2b7a2a8ee79a8d052ee9286501919966e17 (refs/remotes/svn/UnwantedFeature) M src/BranchExample.java r18 = f28e6dd9b3f0929b55d2d92a3785de35db1036d3 (refs/remotes/svn/UnwantedFeature) Checked out HEAD: http://svn.example.com/subversion/Project/trunk r12
The git svn fetch command pulls down the code, including any branches and commit history associated with the files. You can check this out by running git log on one of the files:
git log src\BranchExample.java commit 7c9a8ef5f5f79b15d510734d0c428f069aec12d8 Author: Git User <git@fantail.io> Date: Wed May 10 01:52:57 2017 +0000 Added a hotfix git-svn-id: http://svn.example.com/subversion/Project/trunk@12 ac2ac16-9d07-11e6-a42d-b97f5eeee0cb commit 026d475e8659205bd85425bbf824b5e0c2cd058e Author: Git User <git@fantail.io> Date: Wed May 10 01:38:27 2017 +0000 git-svn-id: http://svn.example.com/subversion/Project/trunk@7 cac2ac16-9d07-11e6-a42d-b97f5eeee0cb
git branch -a * master remotes/svn/Feature1 remotes/svn/Feature2 remotes/svn/Feature3 remotes/svn/UnwantedFeature remotes/svn/trunk
git branch dev/Feature1 remotes/svn/Feature1 git branch dev/Feature2 remotes/svn/Feature2 git branch dev/Feature3 remotes/svn/Feature3 git branch dev/Feature1 dev/Feature2 dev/Feature3 * master
The reason I'm not calling them "feature" branches is that I want to use Git Flow in future (follow the link for the best explanation I have ever seen) and this assigns a special meaning to the feature branch. I don't want conflicts later on, so I've decided that these SVN branches will become "dev" branches.
Once you've linked all the branches you need you can share your repository with the rest of your team. I covered creating a remote repo in Visual Studio Team Services in the previous post, and of course you can use a different hosted Git repo such as BitBucket or GitHub if you want to. Once you have created your remote, link it using:
git remote add origin ↩ https://x.visualstudio.com/GitDemo/_git/Project
git fetch warning: no common commits remote: remote: vSTs remote: vSTSVSTSv remote: vSTSVSTSVST remote: VSTS vSTSVSTSVSTSV remote: VSTSVS vSTSVSTSV STSVS remote: VSTSVSTSvsTSVSTSVS TSVST remote: VS tSVSTSVSTSv STSVS remote: VS tSVSTSVST SVSTS remote: VS tSVSTSVSTSVSts VSTSV remote: VSTSVST SVSTSVSTs VSTSV remote: VSTSv STSVSTSVSTSVS remote: VSTSVSTSVST remote: VSTSVSTs remote: VSTs (TM) remote: remote: Microsoft (R) Visual Studio (R) Team Services remote: Unpacking objects: 100% (3/3), done. From https://x.visualstudio.com/GitDemo/_git/Project * [new branch] master -> origin/master
git push --all Counting objects: 33, done. Delta compression using up to 4 threads. Compressing objects: 100% (23/23), done. Writing objects: 100% (33/33), 3.25 KiB | 0 bytes/s, done. Total 33 (delta 11), reused 0 (delta 0) remote: Analyzing objects... (33/33) (3 ms) remote: Storing packfile... done (112 ms) remote: Storing index... done (26 ms) To https://x.visualstudio.com/GitDemo/_git/Project * [new branch] dev/Feature1 -> dev/Feature1 * [new branch] dev/Feature2 -> dev/Feature2 * [new branch] dev/Feature3 -> dev/Feature3 ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://x.visualstudio.com/GitDemo/_git/Project' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
git pull origin master From https://x.visualstudio.com/GitDemo/_git/Project * branch master -> FETCH_HEAD fatal: refusing to merge unrelated histories
You'll see I got an error - my master branch and the origin's are different because I told VSTS to add a .gitignore file for me and it committed that as a first change. This means that my remote and local repositories have different commit trees. Fortunately we can merge them together using:
git pull origin master --allow-unrelated-histories From https://x.visualstudio.com/GitDemo/_git/Project * branch master -> FETCH_HEAD Merge made by the 'recursive' strategy. .gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .gitignore
git push --set-upstream origin master Counting objects: 2, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 351 bytes | 0 bytes/s, done. Total 2 (delta 0), reused 0 (delta 0) remote: Analyzing objects... (2/2) (1 ms) remote: Storing packfile... done (69 ms) remote: Storing index... done (28 ms) To https://x.visualstudio.com/GitDemo/_git/Project 481b41c..3925ba0 master -> master Branch master set up to track remote branch master from origin.
Comments
Post a Comment