Here’s what I keep reading:
With distributed version control, merges are easy and work fine. So you can actually have a stable branch and a development branch, or create long-lived branches for your QA team where they test things before deployment, or you can create short-lived branches to try out new ideas and see how they work… This is possibly the biggest advance in software development technology in the ten years I’ve been writing articles here. – Joel Spolsky
Or:
But this is git. Branches are easy. You should use them. You should use them more than you do. And I’m confident in saying that, because I’ve never yet met anyone (myself included) who branches as often as they should. -Dominic Humphries
I don’t know what brand of crack my esteemed colleagues are smoking, but merge is in fact totally something to worry about. Step into my world…
A .pbxproj file is basically the “This is the project” file for XCode. It’s written in what looks to the untrained eye like a strange superset of JSON. Every time you add or remove any files to the project, this file gets modified by magical closed-source tools. It turns out that for most trivial changes a simple “left, then right” in your diff tool of choice will solve the problem. But that’s every time you merge anything. And may God have mercy on your soul if you’ve mucked with XCode’s organization structure.
It used to be the case that XCode would crash if you did a nontrivial change to this file while it was open. I think they fixed it last year, but you have many generations of Apple developers who say a prayer before merging anything. Also, they continue to invent new and novel ways of holding project metadata that include, at the time of this writing, about four different XML files that sometimes come along for the ride.
So a xib (sometimes called “nib” for historical reasons) is sort of the answer to Microsoft’s XAML (Well, xib came first. Perhaps it’s the question to which XAML is the answer?) It’s a file that describes how the user interface is laid out that gets fed to a compiler. Let’s leave aside the flamewar about whether or not this is a good idea (it gets some play now and again) and focus on the fact that we do have a project and it does use this.
But the key difference with XAML is that nobody really understands the xib format outside of Cupertino. I mean, it’s basically XML, but XML is an alphabet, not a language, and that doesn’t really help. You can probably find some neckbeard who reverse engineered it two versions ago and maybe his knowledge is current, and you can probably guess what is the right thing to do in common cases.
End result: Every time two people nontrivially work on the same screen, a neckbeard is summoned, and people use guess-and-check, the same method they teach fourth-grade math students, to do the merge.
Oh, and by default the system diff tool does this weird preprocess step before it displays the file, I guess to try and give you better-than-zero insight into what actually changed. Result: can’t choose hunks.
So here’s how I envision this one being invented:
Engineer 1: “You know what we should do? You know those xib files that cause merge conflicts every time two people touch the same screen?”
Engineer 2: “Yeah?”
Engineer 1: “I think we should announce, as a headline feature of iOS 5, that now you can pack all of those into one file, so that every change to any UI anywhere conflicts with every other change to every UI everywhere.”
Engineer 2: “Great idea!”
This is essentially Core Data’s version of xib, that changes every time you update any data model. The good news is, it is sort of easier to understand the contents of the file even if you’re not a neckbeard, so it is sort of easier to merge.
The bad news is, there is a nasty bug in XCode that causes the incremental compiler to re-use old versions of the data model in your builds. So whenever you muck with this file outside of XCode, you must always remember to clean build, or you will keep reporting bugs to the data model people that don’t really exist.
So I don’t know about you, but I end up with a lot of stuff that I need for unit tests. For example, I have a test suite that runs on a fairly large dataset. This dataset is frozen in a SQL blob and checked in to the repository so that mere mortals can run the test suite. Every time I change my data schema, I also have to refactor that blob so that the tests pass. And there’s no way to merge sample data.
Or, I do isolated client/server testing, and I have a blob somewhere that stores the responses of a server that I recorded once upon a time. If the server changes behavior for whatever reason, I have to update the blob. Maybe I do it on two branches, and they don’t merge cleanly.
Branching and merging is not “all that easy”. Maybe you’re not an iOS developer and so 4/5 of my examples don’t apply to you, but even 1/5 is a barrier to clean merges, unless you don’t have a comprehensive test suite. (And you do…. right? Right?)
In theory, we can do something about this. Git has this thing called “merge driver” which lets you inject custom merge behavior for particular file formats. In theory Apple (or heck, ordinary people) could write such a thing, as far as the reverse engineering allows. In practice, nobody has even bothered to write a merge driver for XHTML, so that should give you some idea of what’s been done here.[0] There’s a thing that could probably be adapted for XML, but it seems to have been abandoned.
If you want to claim that the merge problem is solved, you have to first have merge drivers for all the formats. As far as I can tell, we have merge drivers only for plain text.
[0] One of the few people who has looked at the problem seriously has concluded: “So, overall, it looks like this is a much harder problem than I initially thought.”
Comments are closed.
Enlightening and entertaining, thank you. I knew there was a good reason I subscribed to this blog. I was very late to the git club, and started using it in Xcode only recently. I too found some alarming issues when incorporating branching and merging into my workflow. So I don’t use git for that. However, as a simple and highly effective “what has changed since my last commit??” test, it has added a lot of confidence to my workflow.
After adding a .gitattributes and
`*.pbxproj binary merge=union`
I’ve never had problems with .xcodeproj merging.
.xibs, on the other hand….
It’s actually the first example on the Git Attributes page in the Pro Git book
http://git-scm.com/book/en/Customizing-Git-Git-Attributes
The trick I’ve used to successfully merge .xib files, .pbxproj files, etc.. is this:
`git merge –no-commit -s recursive -X theirs `
The -“X theirs” tells git to favor “their” changes, which is the branch your merging from.
—
The other, far less elegant way I’ve done these is to reject the conflicted .pbxproj and .xib files, and manually copy them from the branch.
I’m glad I’m not the only one who has these kinds of issues with merging and branching (regardless of the source control tool). Maybe it’s no big deal if what you are doing is pure curly braces source code.
If you have an IDE or some kind of visual designer storing things in a file, merging becomes a horrible prospect. Depending on how the tool feels like updating its file, it could be that your version of the file and my version of the file might as well have not even originated from the same ancestor. I get chills up my spine when I think about merging something like a BizTalk orchestration.
Those aren’t the only examples. You never needed to put Word/OpenOffice specs inside a repo? At my old company we ended up unpacking OpenOffice files (hey, they are ZIPs!) and storing them in the repo, but it’s not cool.
That’s one advantage for LaTeX or Markdown. However, standard merge drivers are inadequate there too, as soon as somebody hard wraps those files.
The thing is, before things where much worse.
Yep; layout-based languages are also mostly fine. But only git got there – branching with Subversion was much more painful, since SVN couldn’t figure out whether some changes on the branch had previously been merged. And that is why people praise git.
Moreover, even source code is not really fine – merge tools don’t understand the semantics of files. But “semantic merge” tools for different programming languages, solving that problem, are being investigated in academy.