xcdiff: comparing two .xcodeproj files the way git compares text
A tool which helps you diff xcodeproj files.
At a glance
- What is it?
- xcdiff is a Swift command line tool and framework that reports differences between two Xcode project files, aimed at teams moving from hand-edited projects to generated ones. It compares, it does not merge, and it is only as good as the comparators you extend it with.
- Who is it for?
- Adopt xcdiff if your team already generates Xcode projects with XcodeGen or Tuist and needs a repeatable check that the generated file still matches the hand-edited original. Skip it if you need merge or apply behaviour, or if you work on a project that has only one .xcodeproj and no second file to compare against.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 31 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a plain text diff is not enough for a .xcodeproj
An .xcodeproj is a directory of plist files, and the interesting parts of it, targets, build phases, file references, build settings, are spread across several of them. Two projects that behave identically can hold those settings in a different order or in a different file. That is the gap xcdiff is built to fill. Its description calls it a tool that helps you diff xcodeproj files, and the README makes the analogy explicit: it can be thought of as git diff for .xcodeproj files.
The audience is narrower than that phrase suggests. The listed use case is project generation, where a team replaces a checked-in Xcode project with one produced by a generator such as XcodeGen or Tuist. Before flipping the switch, you want evidence that the generated file reproduces the original one, target by target, file by file. xcdiff gives you that comparison as a report you can read in a terminal or capture in CI. It is a verification instrument for a migration, not a general purpose project editor, and the project ships no mechanism for writing changes back into either file.
Comparators run across targets, sources and headers
Running the executable inside a directory that holds two .xcodeproj bundles makes xcdiff search for them and apply all of its comparators to the pair. The README names the comparator families as targets, sources and headers, and it also describes the tool as extensible, so the set of comparators is a code-level decision rather than a fixed user-facing list.
The repository layout backs this up. The Sources directory holds the command line target and, separately, a Core framework that the README tells you to add as a dependency of your own macOS project. The attribution list credits XcodeProj for project file parsing and SwiftPM for the utility library. So the flow is: read two project files through a parser, run each comparator over the parsed model, and print the differences. The verbose flag switches on a detailed report of what differs rather than just the fact that something differs.
The library framing matters for how you deploy it. Because XCDiffCore is a separate framework with its own documentation page, a team that wants a project generation check embedded in its own tooling can call the comparators directly instead of shelling out and parsing terminal output.
Building the CLI yourself, and the commands that back it
The README points at Documentation/Installation.md for a CLI install and a framework dependency, and points at Documentation/CLI.md for the option reference. The Makefile in the repository root is the concrete build path for people who would rather compile it themselves. It builds a universal binary for both architectures and cleans before installing to /usr/local/bin.
xcrun swift build --disable-sandbox -c release --arch arm64 --arch x86_64The same Makefile exposes the test target, which runs the Swift test suite with coverage enabled, and a clean target that clears the SwiftPM build directory. Both of these are the commands to reach for before you trust a comparison result.
xcrun swift package clean
xcrun swift test --enable-code-coverageVersion bumping is scripted too, with sed rewriting the version constants in Sources/XCDiffCommand/Constants.swift and the install documentation in lockstep, so the CLI can print the exact build it came from. A separate target bumps the Homebrew formula to the same version, which tells you the project expects a Homebrew installation to exist alongside source builds.
A first real comparison with two named projects
The tool's simplest invocation needs no arguments beyond the two projects you want to compare. Given an original project and a generated one, name both explicitly with the -p1 and -p2 options:
xcdiff -p1 OriginalProject.xcodeproj -p2 GeneratedProject.xcodeprojThe README includes a screenshot of what this prints, described as example output. The same comparison with the verbose flag, short form -v, produces a detailed report of differences:
xcdiff -p1 OriginalProject.xcodeproj -p2 GeneratedProject.xcodeproj -vTwo details are worth noticing. First, the two paths go into named flags, -p1 and -p2, so a swapped pair is visible in the command itself, which matters when you are trying to decide which side is the reference. Second, running the tool with no path arguments in a directory containing two projects is a different entry point from the same code, so a CI step that runs in the wrong directory will silently look for projects rather than fail on a typo. The README also suggests running xcdiff --help for the option list.
The verdict of a run is a difference list, so the natural use is a threshold: if the comparison is empty, the migration step is a no-op, and if it is not, you get a list of what to investigate.
Where xcdiff stops being the right tool
The largest limit is scope: xcdiff reports, it does not act. There is no documented apply, merge, or write-back mode in the CLI documentation the README points to, and no mention of conflict resolution. If two projects differ in a way you want to reconcile automatically, xcdiff hands you a description of the disagreement and leaves the decision to you.
The second limit is what the comparators know. The README names targets, sources and headers as the comparator families, and it does not publish a full list of every field inspected, including build settings, build phases, signing, or entitlements. For a project where a wrong value in a build setting would break signing in release builds, that gap matters, and you should read the comparator sources before treating an empty diff as proof of equivalence. The word extensible in the README cuts both ways: a missing comparison can be added, but only by writing code against XCDiffCore.
The third limit is platform and format. This is a Swift package built with xcrun and SwiftPM for macOS, aimed at .xcodeproj files. There is no Linux path described, and no mention of the newer .xcworkspace or Xcode 16 file system synchronized groups. A team whose build definition moved to those structures should verify coverage before trusting the tool.
Compared with raw plist diffing and manual inspection
The obvious alternative is to diff the plist files directly. A .xcodeproj can be opened as a package, and its project.pbxproj is a plist, so text comparison tools can be pointed at it. The difference in approach is that raw diffing compares serialized text, where key order and formatting changes read as differences, and it reports no notion of what a target, a source file, or a header actually is. xcdiff works from a parsed project model, so its comparators can express intent: does the original have a source file that the generated project lacks, rather than does line 412 differ.
The other alternative is human inspection, opening both projects in Xcode and comparing targets by eye. That is accurate in principle and does not scale, which is the argument the project makes for a repeatable command. The trade-off between the two is what the README does not quantify: there is no benchmark in the documentation comparing xcdiff output against manual review on a large project, so for a one-off migration a human pass may be faster than learning the tool.
For teams already running XcodeGen or Tuist, xcdiff fits a pipeline slot that manual review cannot fill, since it can run as a build step and fail on a non-empty diff.
Release cadence, the Apache-2.0 licence, and what upkeep means here
The most recent release listed is version 0.14.0, published on 2025-09-08, preceded by 0.13.0 in February 2025 and 0.12.0 in April 2024. The project follows semantic versioning, which the README states directly, so the zero major version means the API of XCDiffCore can still move between minor releases. Anyone embedding the framework should pin an exact version rather than track a range.
The repository is not archived, and the last push was on 2026-09-22, so the code base is being worked on as of that date. Note the gap between that push date and the last tagged release: recent commits are ahead of what 0.14.0 shipped, which matters if you pin a released version and assume you have everything on main.
The licence is Apache License 2.0, referenced from LICENSE.txt in the repository root. Permissive, with the patent grant and the notice requirements that come with it. Bloomberg publishes it under [email protected] for security reports, and asks that vulnerability reports go by email rather than as public issues, which is a useful signal about how they want disclosure handled. The project also carries a Code of Conduct and contribution guidelines, with pull requests preferred over issue reports for fixes.
Editorial conclusion
Adopt xcdiff if your team already generates Xcode projects with XcodeGen or Tuist and needs a repeatable check that the generated file still matches the hand-edited original. Skip it if you need merge or apply behaviour, or if you work on a project that has only one .xcodeproj and no second file to compare against. Before wiring it into a pipeline, check two things yourself: run the CLI against a pair of projects you already know differ, and read the comparators in Sources/ to see whether the fields your build depends on are actually covered, since the README names targets, sources and headers but does not enumerate every comparison.
Frequently asked questions
How do I compare two Xcode project files with xcdiff?
Run xcdiff with the -p1 and -p2 options pointing at the two .xcodeproj bundles, or run it with no arguments in a directory that contains two of them. Add -v for a detailed report of the differences.
Can xcdiff merge or apply changes between Xcode projects?
No documented capability does that. The README describes finding and reporting differences between two project files, with no apply or merge mode mentioned in the CLI documentation it points to.
Is xcdiff actively maintained and what licence does it use?
The repository is not archived and the last push was on 2026-09-22. The README states that xcdiff is released under version 2.0 of the Apache License, with the licence text in LICENSE.txt.
How do I install xcdiff as a command line tool?
The README links to Documentation/Installation.md, which has a CLI section and a Framework section for adding it as a dependency of a macOS project. The repository Makefile also provides build, install and test targets driven by xcrun swift build.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bloomberg-xcdiff)Was this useful?