Friday 8 February 2013

digging out of gitsvn holes...

I've been doing a lot of work with one of our remote teams recently to help them get going with automating their build and test life cycles. Which has involved one of my "favorite" things in the world maven wrangling. This has been particularly frustrating because the team in question are our front end team and our front end is built using Adobe Flex. Flex and maven are not friends, I have developed a huge amount of respect for the work of Velo in building flexmojos, which leads to a lot of pain. Now a lot of the pain is probably self inflicted as I know very little about Flex and Air however any maven build which requires remote debugging to under stand what is going on has problems... I have however won my fight with maven & flexmojos and our web and desktop clients build through maven!

One of the other bits that has made life a lot more complicated around this process is the fact that our front end team use SVN and we use git. One of our first goals was to have a mirror of the source code and because we use git and more specifically github we wanted it in there as well.

I've set the mirror up by creating a blank repo in github (adding a readme file or anything else to the repo just makes life hard.), and doing a git svn clone of the svn repo on one of our build boxes.

 git svn clone https://svn.repo/trunk   

Normally you'd use something like -s for standard layout however the permissions on this svn repo are a bit restrictive so trunk it is.

I've then manually added the github repo as origin to the gitsvn checkout. e.g.

 git remote add origin git@github.com:SamBarker/testing.git  
 git push -u origin master  

Then we use a cron job which goes into the git root and does a rebases against the svn repo, pulls in master and then pushes the results out.

 git svn rebase  
 git pull origin master && git push  

This all works rather nicely really. I can restructure and mess about in my own git branch blithely ignoring svn to my hearts content rebasing my branch against master to stay current with the wider world. However  things all go a bit Pete Tong when I need to merge back. For a start, I work on mac, our build servers are linux and the front end team use windows. So the good old LF -v- CRLF fight ensues. Now I'm not one for forcing things on people so why can't I and the build servers just use LF and the windows guys wonder along in their funny little world? I'm sure there are better ways todo this but the path of least resistance at the time, and avoiding having anyone else make changes to their setup. I've set git up to try the right thing with line endings.

 [core]  
      autocrlf = input  

However it seems like git svn doesn't play to nicely with that setting. So we have a problem occasionally, and I've not figured out why, I end up with spurious changes on update which don't go away with a git reset --hard. These "phantom" changes are the line endings or maybe filemodes being futzd with. However their just a PITA so lets get rid of them. Our cron job now looks like:

  #line endings keep getting f***ed over  
  git rm --cached -r . && git reset --hard  
  git svn rebase  
  git pull origin master && git push  

Which gets us back to a nice sane world.

So there is a bunch of advice out on the web about how to set up git svn syncing most of which I found after trying to dig my self out of various self induced holes.

The major mistake that really was tough to dig my self out of was when we ended up with a change in the git repository which has been pushed back out to svn but git svn failed to recognise that that the merge had happened. So everytime we rebased from svn we would see a merge conflict on the same file. However even resolving this conflict the next rebase would have exactly the same issue. Now this took me ages to truly realise but my git checkout is a true git repo and git svn is pulling into its own branch and rebasing your branch against that.

 
 master  A---B---C---1  
         ^           ^   
         |           |  
         |           |  
 git-svn A---B---C---D  
 becomes   
 master  A---B---C---D---1  
         ^           ^  
         |           |  
         |           |  
 git-svn A---B---C---D  
 however   
 master  A---B---C---1 ---?  
         ^           |    ^  
         |           |    |  
         |           V    |  
 git-svn A---B---C---1'---D  

This all get a bit odd at this point. Logically you can get 1 merged back in to master and the world to look sane but gitsvn really hasn't understood this. However the fact that git-svn is a branch in its own right comes into its own here because you can fix this mess with just one command.

 git reset --hard git-svn  

Now you should only run that if your confident that all your changes are actually in svn because what your doing is telling git force `master` to be the content of `git-svn`.