Just how smart is Git?
Posted at 07:00 on 28 June 2010
The merge algorithms in distributed source control are a vast improvement on Subversion, which falls over on all but the simplest cases, but contrary to the claims of some, they are not omniscient.
For example, it is commonly believed that Git can track functions being moved from one file to another, and merge in the changes appropriately. It’s a plausible claim—I’m pretty sure that such a merge algorithm is doable—and it would also be particularly useful, since it would open up several more possibilities for the kind of refactoring that you can manage in a distributed workflow with parallel work streams.
Of course, this is very easy to test, so on Friday evening, I decided to test it.
I loaded the code for the latest version of my Comment Timeout WordPress plugin into a new git repository and created a branch called Alice. I then edited the file class.post-processor.php to add a comment in the constructor, and checked it in.
I then switched back to the original version and created a branch called Bob. I cut the constructor from class.post-processor.php and pasted it into class.comment-processor.php, and checked the resulting changes into Bob. I then attempted to merge Alice and Bob.
Lo and behold, I got a merge conflict.
Both Git and Mercurial support a merge-over-rename scenario which Subversion doesn’t: if Alice makes some edits to foo.txt and Bob renames it to bar.txt, Alice’s changes to foo.txt will be correctly merged into Bob’s bar.txt. I haven’t done any more exhaustive testing than that, but I suspect that Git and Mercurial have overall roughly similar merging capabilities, though undoubtedly there will be some edge cases that one handles that the other doesn’t, and vice versa.
It seems that the biggest difference is that Git uses various heuristics to automatically detect file renames, whereas Mercurial expects the user to flag them explicitly. Which approach is better is controversial, but Mercurial users who prefer Git’s behaviour in this respect may be interested in this experimental extension to detect and register obvious renames at commit time which I knocked together over the weekend.