Sunday, 3 November 2013

Version Control for Go

When I first heard of version control, the most popular ones at the time were probably CVS and subversion. It seemed like every open source project used one. I understood their value for collaboration but not as a sole developer so I steered clear of them for a long while. However, they kept coming up and eventually there were some new kids on the block which were vying for attention: Git, Mercurial and Bazaar. Now, this isn't a history lesson of any kind or some kind of detailed comparison of them all. There’s plenty of that already out there. Instead, this is a short explanation of which one I chose to use when programming in Go and why.

I recall reading a book on C programming which had a section on Subversion. I tried it out. I didn't understand it. There were a lot of do’s and don’ts and I found it very intimidating. I understood the value but hated using it. Why did I have to keep track of changes anyway if I wasn't sharing the code? As time went on and I wanted to finally work on my first major project, however, I knew I was going to need a method of tracking my changes even if I didn't share my code. Too many times I'd get part way through working through a feature, realize I didn't like it or it didn't work, and realize it was too late to go back (or would take a lot to revert the changes. This left me little choice but to look at version control, again.

Fast forward a few years and I finally installed a GNU/Linux distribution that really clicked with me: Ubuntu. Long story short, I discovered Ubuntu used a version control system called Bazaar and after reading a few articles telling me how easy it was to use I decided to give it a try. A lot of mistakes later I finally figured out how to use it and I loved it. Bazaar was simple and easy to use. I really liked that the commands were clear in their purpose and the defaults felt natural. I could clone a repository into a new directory with a specific name, make changes (like a hot-fix or new feature), then merge that directory back into the main repo. and the name stuck with it! Forever I would know that a series of commits belonged to a fix or feature with that name. Loved it!

As time went on, I began to discover that Bazaar was the least favoured of the 'big three' distributed version control systems. At first this didn't matter to me but it started to make me wonder if I'd made the right choice. Indeed, Git and Mercurial both had much larger share of the market, as it were. But, Git scared the hell out of me. It had so many commands and features that it still made me feel truly lost, even after using Bazaar for close to a year.

I had just discovered Go and, perhaps naively, I thought that if I were to create a Go library I should use Google Code hosting, just like Go did! The problem being: no support for Bazaar. This was a problem I found everywhere except Launchpad and Sourceforge. No other popular code hosting site supported Bazaar. But, many of them did support Mercurial and guess what? Mercurial was just like Bazaar but, perhaps, even better.

Mercurial welcomed me with open arms! It supported the same workflow and the commands were all almost identical. Now I had a wider choice in code hosting too.

Again, as I stated already, I was discovering Go. And one thing that Go doesn't like is when sub-directories change. Let me give an example. Lets say you’re using Google Code to host your project. Let’s call the project an imaginative name. Let’s call it: foo. So you’d import that library from “code.google.com/p/foo”. Maybe I want to make a fix. What I would typically do is clone my project into a new directory called foo-name-of-fix. Now, let’s say I want to run the test framework to make sure it passes and I didn't mess something up. If I just run ‘go test’ it will import from “code.google.com/p/foo” NOT from the repo. I just created, which would be “code.google.com/p/foo-name-of-fix”. That meant, every time I made a new directory I’d need to change everything. And, make sure you change it all back before merging! A headache to be sure!

Now, this isn't the only way to do it in Mercurial. You can used named branches or tags. There are ways to overcome this problem. But again, these were workarounds and it was like “a splinter in my mind” driving me crazy. I was also aware that the most popular version control was Git.

So, I tried it. And this time I’d accumulated enough experience that I wasn't completely overwhelmed. Yes, Git has a shit-ton of features. But, you don’t need to use them. You don’t even have to know they’re there. You just need to know the basic commands and ask questions (most questions have already been asked on Stack Overflow so a quick search is usually the best thing to do) when you get stuck or if something bothers you. Because in Git, there’s almost always an answer.

I didn't immediately like Git but one thing I really liked was that named, in-directory branches were the natural way to do things. It made working with Go brutally easy. I didn't like that the name is discarded once you merge and delete said branch. I really liked that Git doesn't assume that just because you made a change to a file you want to commit it. This is a feature I didn't like at first but that I've grown to like. You can use a shortcut when committing to get the same behaviour as Mercurial and Bazaar but otherwise it will force you to manually add those files you want to commit. Very nice for cherry picking changes.

There are things I don’t like about Git. Many of it's features are reserved for corner cases and it’s still a bit overwhelming at first even though the Git community has done a tremendous job alleviating that particular problem. There are a million and one ways to do the same thing with their own pros and cons making it sometimes difficult to know which is the right solution for you. I’m not overly fond that branch names aren't attached to a commit series after merging, either.

Conclusion

I don’t want to mislead you. I still like, and use, Mercurial. As a matter of fact, my main project goncurses uses it still and I have no plans to change that. The Go project itself also uses it. I do, though, find myself missing Git sometimes and the reverse is not true when using other version control systems. I can’t really say why I find myself liking Git better but its just a feeling I get that I can’t put my finger on. Were I to make a recommendation it would be Git because it plays nicely with Go within its 'default' workflow but to be perfectly honest very similar behaviour can be done in Mercurial so you can't really go wrong with it either. It's a very close second. You just need to be aware about the issue with using cloned branches.

Depending on your workflow and habits, you may need to be flexible when using a VCS like Mercurial with Go. My needs are simple and the adjustment wasn't hard. Depending on what you’re used to, no adjustment at all may be necessary.