I've recently joined a project team working on an iOS app. On joining I introduced a script I've used before which assists in dealing with the dreaded Xcode project file merge issue. Essentially this issue comes up when you have multiple people all working on the same XCode project.
XCode keeps it's core project settings in a single file called
<your-project>.xcodeproj/project.pbxproj. It contains all the files, settings, targets, etc which you see in XCode when developing. This file is essentially a giant plist. Inside it, your source code files and other files are mapped using hexidecimal UUIDs to refer to them.
With multiple developers working on the same project, clashes will occur as they make changes to the file list. To make matters worse, XCode does not store the files references in any particular order and regaularly re-writes it in a random order. So if two developers make changes to the list of file including in the project (adding, deleting or renaming), it can be near impossible to figure out the changes in a merge editor.
The best way to deal with this is to implement a pre-commit hook in Git which sorts the contents of the pbxproj file just before you commit it. This means that when a merge issue occurs, rather than trying to compare two unsorted lists of files in the pbxproj merge, the lists are now sorted, making changes much easier to locate. The program I use for sorting is the SOCK python program. I'll do another post on customing it for Workspace projects.
So how does this work with CocoaPods?
In a word - it doesn't.
By default XCodes writes out the pbxproj file in a old JSON like format that originated many years ago. The pbxproj file is actually a plist file so it can be stored using a couple of different formats, the older JSON like format or XML, which is what Apple appear to be moving towards. But for the moment, XCode will only write the file in the old format. This is the format that SOCK understands.
CocoaPods on the other hand, needs to update the pbxproj file, but will only write this out in XML. The story is that Apple have deprecated the OS X API for writing files using the old format so CocoaPods and indeed, any other application that needs to write a plist style file, can only write in XML.
So the problem becomes that the pbxproj file sorting code I need to use only understands the old format, whilst CocoaPods only writes in the newer format. I've searched for an alternative sorting program that can handle the XML formatted pbxproj filesbut so far I've had no luck in finding one.
The effect of this issue is that I often get merges where Git thinks the whole file is different because CocoPods has completely re-written it. And, having been re-formatted, it's now unsorted.
How do I get around this?
Currently I'm following this procedure when I get a merge that says the whole file is different:
- Clone the remote project into a new directory and ensure that the pbxproj file sorting is installed into the git hooks.
- Open the project in XCode and make/unmake a minor change to the project to trigger the writing of the pbxproj file in the older format.
- Commit the pbxproj file and push to the repo.
- Pull the changed pbxproj file, which will now be mergable.