views:

110

answers:

3

I migrated our SVN repository to Git and pushed it to a central repository. We had a fair amount of tags and branches, but somehow we were not able to list and fetch those from a Git client. This was weird, because the tags and branches seemed to be available on the server.

With help from a Jon Maddox blog post, a blog post from Marc Liyanage and a SO answer from Casey I was able to stitch a solution together. Thanks for all the help!

Here's what I ended up doing. First I created a file with the svn committers:

local$ svn log svn://server/opt/svn/our_app |grep ^r[0-9] | cut -f2 -d\| |sort |uniq | tee ~/users.txt
alice
bob
eve
local$ vim ~/users.txt
local$ cat ~/users.txt
alice = Alice Malice <[email protected]> 
bob = Bob Hope <[email protected]>
eve = Eve Leave <[email protected]>

Then I created a git repo from our svn repo:

local$ mkdir our_app
local$ cd our_app
local$ git svn init --authors ~/users.txt --stdlayout svn://server/opt/svn/our_app --stdlayout 
local$ git svn fetch
local$ git svn create-ignore
local$ git commit -m 'added .gitignore, created from svn:ignore'
local$ for remote in `git branch -r`; do git checkout -b $remote $remote; done  

This last step was crucial, since otherwise branches/tags were not available when cloning from a remote repository. Anyway, I pushed this to a new remote repo:

local$ ssh server
server$ mkdir /opt/git/our_app.git
server$ cd /opt/git/our_app.git
server$ git --bare init
server$ git config core.sharedrepository 1
server$ git config receive.denyNonFastforwards true
server$ find objects -type d -exec chmod 02770 {} \;
server$ exit
local$ git remote add origin ssh://server/opt/git/our_app.git
local$ git push --mirror

A fresh clone of the remote repository showed that everything was available:

local$ git clone ssh://server/opt/git/our_app.git
local$ cd our_app
local$ git branch -a
* master
  remotes/origin/master
  remotes/origin/pre-svn-move
  remotes/origin/tags/mytag-0.1
  remotes/origin/tags/mytag-0.2
  remotes/origin/trunk
  remotes/origin/mybranch-1
  remotes/origin/mybranch-2

Now a remote branch could be checked out:

local$ git checkout -t origin/mybranch-1
local$ git branch
  master
* mybranch-1

Just to re-iterate: this guide includes hints for remote tag and branch availability, mirroring to a remote repo and re-use of values in svn:ignore. I hadn't found all of these in one guide earlier.

A final note: ebneter's tip about svn2git was also great, since this one actually preserves tags as tags, while git-svn converts them to branches. On the other hand, I couldn't get "git svn create-ignore" to work with svn2git...

A: 

The only suspicious command I can find in your sequence is the

git config branch.master.remote origin

First, your first local repo (from the git svn fetch) should have branches, not remote branches.

Second, your server repo (which does have the right branches), should be able to be cloned with all its refs, meaning the second local repo should list all the remote branches.

Could you try the git svn fetch without the git config branch.master.remote origin?

VonC
The branches are shown as remote from the beginning, immediately after "git-svn fetch". The "git config branch.master.remote origin" doesn't seem to have any effect at all, I've tried the whole sequence without it.
neu242
@neu242: interesting. What I don't understand is why the branches are listed in the server repo after your push --mirror. Anyway, for the first local repo, try tracking all remote branches before pushing it to your bare repo: http://stackoverflow.com/questions/379081/track-all-remote-git-branches-as-local-branches
VonC
OK, I did a "git branch --track" for all the branches before the initial push. Now all branches/tags are listed similar to both "remotes/tags/mytag-0.1" and "tags/mytag-0.1". Then I did a "git push --mirror". All tags and branches are now listed twice (without remotes/*) on the server. But after a fresh "git clone ssh://server/opt/git/our_app.git" on the client, "git branch -r" lists all tags/branches as they should (not twice). So this is good. Should I worry about the dupes?
neu242
Something is odd. If I do a "git checkout -b mybranch-1 origin/mybranch-1" I get the latest trunk. It doesn't seem like any of my tags/branches differ at all.
neu242
+1  A: 

If this is intended to be a one-way conversion (never going back to svn) I would strongly suggest using svn2git as it greatly simplifies the whole thing. To do the conversion, you basically do

svn2git <svn repo url> --authors <author names & emails file>
git remote add origin <git bare repo url>
git push --all
git push --tags

... that's really all there is to it.

ebneter
ebneter: Yeah, I tried nirvdrum's svn2git (there are several!) before I saw your answer yesterday, and it worked like a charm! It even did the tags properly, which git-svn doesn't. The only problem now is that previous folder moves hasn't been registered properly: when I diff branch1/content to branch2/moved_here/content, it compares the root folders...
neu242
Those are moves done prior to the conversion? Or after?
ebneter
@ebneter: Before.
neu242
+1  A: 

See my answer here:

http://stackoverflow.com/questions/79165/how-to-migrate-svn-with-history-to-a-new-git-repository/3972103#3972103

Casey
Thanks. Those manual git checkout commands for every branch were crucial. svn2git does this better, though, because it preserves tags.
neu242