How do I migrate an SVN repository with custom structure to Git? - git-svn

I have a multi-module legacy project in SVN, where individual modules were released and tagged separately, resulting in the following structure:
trunk/
project/
moduleX/
moduleY/
moduleZ/
tags/
moduleX-1.0/
moduleX-1.1/
moduleY-0.1/
moduleZ-2.0/
Looks like the tags were created with svn copy trunk/project/moduleX/ tags/moduleX-1.0/ etc, rather than svn copy trunk/project/ tags/moduleX-1.0
Is it possible to migrate such project to Git as a single repository, preserving history and creating appropriate tags?

You need to manually configure git-svn.
Create empty repositories: git init moduleX ; git init moduleY ; git init moduleZ
Edit each gitconfig and add a git-svn section like:
moduleX/.git/config:
[svn-remote "svn"]
url = svn://your-server/svn-repo
fetch = trunk/project/moduleX:refs/remotes/svn/trunk
tags = tags/moduleX-*:refs/remotes/svn/tags/*
moduleY/.git/config:
[svn-remote "svn"]
url = svn://your-server/svn-repo
fetch = trunk/project/moduleY:refs/remotes/svn/trunk
tags = tags/moduleY-*:refs/remotes/svn/tags/*
moduleZ/.git/config:
[svn-remote "svn"]
url = svn://your-server/svn-repo
fetch = trunk/project/moduleZ:refs/remotes/svn/trunk
tags = tags/moduleZ-*:refs/remotes/svn/tags/*
git svn fetch in each copy.

Related

What is the Difference Between fetch and branch in the Git config file

The config file of a Git repository has under [git-svn remotes] both fetch and branch paths. The config file can even have multiple fetch lines and multiple branch lines. What is the reason to have (and what is the difference between) both fetch and branch? When I do a git svn fetch --all, I get updates for the trunk in fetch and from all the other branch lines as well. So it seems there is no difference. Is there any drawback if I just list all my branches using multiple branch and not have any fetch line?
[svn-remote "messy-repo"]
url = http://server.org/svn
fetch = trunk/project-a:refs/remotes/project-a/trunk
fetch = branches/demos/june-project-a-demo:refs/remotes/project-a/demos/june-demo
branches = branches/server/*:refs/remotes/project-a/branches/*
branches = branches/demos/2011/*:refs/remotes/project-a/2011-demos/*
As illustrated here, the first git svn clone does generate a cnfig with fetch in it.
If at any point after this you want to checkout additional branches, you first need to add it on your configuration file:
[svn-remote "svn"]
url = https://example.com/
fetch = PROJECT/branches/somefeature:refs/remotes/trunk
branches = PROJECT/branches/{anotherfeature}:refs/remotes/*
The branches config always needs a glob.
From git svn clone
After a repository is cloned, the fetch command will be able to update revisions without affecting the working tree
The difference:
It is similar the core Git [remote] sections except fetch keys do not accept glob arguments; but they are instead handled by the branches and tags keys.

Git clone from svn repo with no trunk directory and place files in root of git repo

I'm importing code from a svn repository with a structure as follows:
Repo/
branches/
tags/
The repository doesn't have a trunk.
Code is kept in the subdirectory ProjectName, so when it's checked out I see
Repo/
ProjectName/
Files
When I execute:
git svn clone -t tags -b branches https://servername/svn/Repo GitRepo
I get a git repository at GitRepo and everything imports correctly, the problem is that whenever I check out files in git it checks them out into the ProjectName subdirectory like:
GitRepo/
ProjectName/
Files
My question is, is there any way way to tell git svn to clone the repo in such a way that I get:
GitRepo/
Files
So, what I'm asking is if I can tell git to use a folder that only appears when a branch is checked out as the root for the repository.
Yes you can do this, but you'll need to specify the trunk, branches and tag locations manually (as they're non standard in your case).
Create you're repo like so: git svn init https://servername/svn/Repo GitRepo
Then open up you .git/config file and the url, fetch, branches and tag lines so that it looks like the following:
[svn-remote "svn"]
url = https://servername/svn/Repo
fetch = ProjectName:refs/remotes/trunk
branches = branches/*:refs/remotes/branches/*
tags = tags/*:refs/remotes/tags/*
The important line here is fetch = ProjectName:refs/remotes/trunk which has created a link between ProjectName on the remote and trunk locally.
Turns out I needed:
[svn-remote "svn"]
url = https://servername/svn/Repo
branches = branches/*/*:refs/remotes/branches/*/*
tags = tags/*/*:refs/remotes/tags/*/*
in .git/config
The second /* in the branches and tags strings being the important part I was missing before.
Thanks to ChrisA for pointing me in the right direction.

How can I change the Prefix Mapping in a Git-Svn Repository?

I've created a Git Clone of a SVN repository using git-svn. When doing this I specified the --prefix option to prefix my remote branches. I now want to get rid of this prefix.
Is there a way to update or remove the prefix without re-cloning the repository?
Essentially I did the initial clone using --prefix=Project so I ended up with Project/trunk and Project/feature-branch as my remote tracking branches. What I want is to have the trunk just be called trunk and the feature-branch be called svn/feature-branch.
I've done the following which appears to have worked.
In .git/config I updated the fetch, branches and tags settings to update the local refs. It was:
[svn-remote "svn"]
url = http://subversion/......
fetch = trunk:refs/remotes/Project/trunk
branches = branches/*:refs/remotes/Project/*
tags = tags/*:refs/remotes/Project/tags/*
Which I changed to
[svn-remote "svn"]
url = http://subversion/......
fetch = trunk:refs/remotes/trunk
branches = branches/*:refs/remotes/svn/*
tags = tags/*:refs/remotes/svn/tags/*
The within .git/refs/remotes I moved trunk out of the Project folder and the remaining refs within Project into a new folder called svn. The structure was:
remotes
Project
trunk
feature-branch
Which I changed to:
remotes
trunk
svn
feature-branch
I also performed the same restructuring of folders within .git/svn/refs/remotes/.
Finally I triggered a git svn fetch. I had to specify the -r argument to limit to the same start revision that I used for my initial clone, but it doesn't appear to have re-fetched the old revisions.
Note: the current solution might not work anymore with git 2.0+ (April 2014)
See commit fe191fc by Johan Herland (jherland), which highlight the fact you now are supposed to have a prefix (and not have a svn branch without prefix like 'trunk'):
Git 2.0: git svn: Set default --prefix='origin/' if --prefix is not given
Having no prefix by default was problematic:
git-svn by default puts its Subversion-tracking refs directly in refs/remotes/*.
This runs counter to Git's convention of using refs/remotes/$remote/* for storing remote-tracking branches.
Furthermore, combining git-svn with regular git remotes run the risk of clobbering refs under refs/remotes (e.g. if you have a git remote called "tags" with a "v1" branch, it will overlap with the git-svn's tracking branch for the "v1" tag from Subversion.

How can you use git-svn to clone parts of an SVN repo, but still get all the branches

Is there any way to use git-svn to clone only some folders of an SVN repo structure. I'm trying to clone a repo that has some crazy big binary files and a number of subfolders that are just plain useless. I've tried using the --ignore-paths option, but my clone seemed to just stall out doing nothing for an extremely long time. Have any of you managed to make --ignore-paths work? I can't find much on the webs where anyone else is running into this. Maybe I'm the only one.
We've used the "ignore-paths" feature to ignore certain directories in a svn repo:
[svn-remote "svn"]
ignore-paths = ^(((branches|tags)/[^/]+|trunk)|)(huge/|mobile/)
This config ignores the "huge" and "mobile" subdirs of the repository in trunk, all branches and all tags.
Perhaps you can illustrate the structure of your Subversion repository to make it easier for us to suggest some solutions.
Are you trying to git svn clone the entire repository from the root-url? Have you tried cloning smaller parts of the repo, and then perhaps grafting several clones together?
The most success I've had here is to manually create branches in git that mirror the SVN remote repository when necessary. The process has been the following:
Update .git/config file with:
[svn-remote "svn-branch-alias"]
url = http://svn/branches/crazybranchname/craziername/url/
fetch = :refs/remotes/git-branch-name
From the command line type: git svn fetch 'svn-branch-alias' to collect the SVN branch data into your local git repo.
Then type: git checkout 'git-branch-name' to go into a headless mode.
Finally type: git checkout 'my-local-git-branch-name' to create move head to the latest submission in that branch and create a local branch alias you can use.
You can now commit and dcommit as usual and still switch between various local git branches and your manually created SVN mirrors using the usual mechanisms.

How do I access svn branches using git-svn with a non-standard svn repo layout?

The standard repo layout in svn is as follows.
/trunk
/branches
featureX
featureY
/tags
1.0
2.0
The repository I'm working with is a much flatter structure.
trunk
featureX
featureY
Essentially, trunk is at the same level as the other branches. I can't use the -s or -b option with git svn init because of this.
How would I pull in trunk as the git branch master and pull in featureX as a git branch of the same name? I don't care about any other branches or tags.
I've seen similar questions and people have suggested restructuring the svn repository. This is off the table as far as this question is concerned.
I've figured out a way to pull in multiple branches from an arbitrary svn repository structure.
The -b option for git svn init will only work if all branches are grouped together within a subdirectory in the repository, such as in the standard layout. If all branches, including the trunk, are side by side in the same folder, this won't really work. You can pull in selected branches from the svn repository by essentially creating multiple "trunks" int your git repository.
Assume the flat structure from the question with the three branches trunk, featureX, and featureY.
Instantiate your git repository.
mkdir myproject
cd myproject
git svn init url:to/svn/repo -T trunk
This will create a git repository with svn metadata in the .git/config file.
Open the config file and examine the svn metadata
vim .git/config
Your config file will look something like this.
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
autocrlf = false
[svn-remote "svn"]
url = url:to/svn/repo
fetch = trunk:refs/remotes/trunk
The svn-remote header defines a reference called "svn" pointing to your svn repository. The fetch parameter tells git-svn where to pull new revisions from within the svn repository. Now we need to tell git-svn about the other branch we're interested in.
Duplicate the svn-remote section
Copy the entire svn-remote section of the config file and paste it below the existing config text.
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
autocrlf = false
[svn-remote "svn"]
url = url:to/svn/repo
fetch = trunk:refs/remotes/trunk
[svn-remote "svn"]
url = url:to/svn/repo
fetch = trunk:refs/remotes/trunk
Modify the new svn-remote section
Change the name of the svn-remote section header and the name of the branch that it points to.
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
autocrlf = false
[svn-remote "svn"]
url = url:to/svn/repo
fetch = trunk:refs/remotes/trunk
[svn-remote "svn-featureX"]
url = url:to/svn/repo
fetch = featureX:refs/remotes/featureX
Now git-svn will track both svn branches. You can use the names "svn" and "svn-featureX" with any git-svn command that takes an [svn-remote] parameter. You can use the names "trunk" and "featureX" with any git command that takes a remote branch name as a parameter.
This solution won't scale well, and is a bit of a hack to work with a malformed svn repository. So long as you only need to track a handful of svn branches, this will work just fine. If the number of svn branches you need to work with becomes too large, take a serious look at restructuring your svn repository to the standard layout.
As this article illustrates, you can write rules for running an importer tool like svn2git
(you have less complete version of svn2git here)
See those examples for rules that you could rewrite in order to match those flat SVN directories/branches and declare them as Git branches.