Kintsugi: Automatically Solving Git Conflicts in Xcode Project Files

by Ben Yohay

Lightricks
Lightricks Tech Blog
4 min readMar 20, 2022

--

Anyone who’s worked with Xcode and Git knows the pain of manually resolving conflicts in the Xcode project file. Rather than live with this problem, we created a tool to solve it. Named after the Japanese art of beautiful repair, Kintsugi is a lightweight way to automatically resolve these conflicts.

The problem

Xcode maintains a .xcodeproj directory that contains information about the project. This package contains (among other things) a huge text file called project.pbxproj. It’s in this file that most merge conflicts occur. The .pbxproj file describes the list of source files, the build phases, the other projects it depends on, and much more.

When using Git or other source control systems, users experience a very common problem: two diverging commits apply changes to the same project file. Often this results in a Git conflict when merging the two commits, even if the commits do seemingly unrelated things (e.g. each commit adds a different file to the project). This happens as a result of the project.pbxproj structure: unrelated changes often affect the same lines, and Git is unable to resolve the collision on its own.

Consider a simple example: The first commit adds the file Foo.m, and the second one adds the file Bar.m. This can result in a merge conflict because they both appear in the same section of the project file:

An example of a merge conflict in the project.pbxproj file.

Until now, the most common way to resolve such conflicts was to take both sets of changes and hope for the best, or resolve the conflicts manually. Both approaches are error prone, as Xcode is very sensitive to the format of the project file. A single error can cause Xcode to refuse to open the project:

In image of the error shown when the merge conflict in the Xcode project file is resolved erroneously.

This is frustrating as it’s not clear what part of the project is corrupted, so at this point you have three options:

- Sift through the file to find the corruption,

- Go back to the merge conflict and try again to resolve it, or

- Discard the changes to the project file and apply them again by repeating those changes on the updated project file.

Kintsugi, on the other hand, is designed to resolve those conflicts automagically.

Git conflicts

Before we dive into how Kintsugi works, we have to understand some Git conflict basics. A Git conflict occurs between two versions of the same file. Let’s call them “version1” and “version2”. Another version that’s useful for the discussion is the common ancestor between the two versions, called the “base” version.

Enter Kintsugi

The idea behind Kintsugi is simple but powerful:

- Extract the meaning of the changes from the diff between “version1” and “base” versions of the project. For example:

Take:

And get: “File Foo.m was added to the project”.

  • Apply those changes to the “version2” branch of the project.
A graph depiciting how Kintsugi resolves merge conflicts.

While Apple doesn’t provide tools for working with Xcode project files, an open-source Ruby project called Xcodeproj, has the ability to do both of these things. Let’s look at a simple example to see how Kintsugi uses both capabilities. Let’s say that the “version1” branch contains a target “Foo” that’s not in “version2”. Kintsugi will carry out the following steps:

  1. Open projects of “version1” and “base” versions with Xcodeproj’s Project object and get the diff:

The diff will contain the target “Foo” as a Ruby hash:

Note the “:added” key in the hash. This marks the changes that appear in “version1” but not “base”.

The hash contains much more information about targets; I’ve removed most of it for clarity.

2. Open “version2” with Xcodeproj’s Project:

3. Apply the diff to “version2” version:

apply_change_to_project iterates over the hash and applies the changes to “version2”. For example, this code handles adding a target:

add_attributes_to_component will iterate over the attributes under the “target” and add them to it.

That’s it. After calling apply_change_to_project, the project file will contain the new target.

Conclusion

Kintsugi has helped many developers in Lightricks speed up their workflow, and we hope that it will help you, too. It’s easy to install using gem install kintsugi, and we’re more than happy to receive issues and fixes to the Github repository in order to further improve its functionality.

Happy merging!

— -

Create magic with us

We’re always on the lookout for promising new talent. If you’re excited about developing groundbreaking new tools for creators, we want to hear from you. From writing code to researching new features, you’ll be surrounded by a supportive team who lives and breathes technology.

Sound like you? Apply here.

--

--

Lightricks
Lightricks Tech Blog

Learn more about how Lightricks is pushing the limits of technology to bridge the gap between imagination and creation.