Skip to content

Instantly share code, notes, and snippets.

@AugustMiller
Last active August 26, 2021 20:28
Show Gist options
  • Save AugustMiller/93ef4c503ee494ebc5f829865f438fb1 to your computer and use it in GitHub Desktop.
Save AugustMiller/93ef4c503ee494ebc5f829865f438fb1 to your computer and use it in GitHub Desktop.
Using Craft’s Project Config on a Distributed Team

Project Config

Project Config is a powerful tool for managing the schema of a Craft application.

However, as with any text stored in version control, it can and will cause merge conflicts when multiple team members make changes to the same system settings.

These problems are exacerbated by Craft's strategy of rebuilding the entire config/project directory whenever a change is made. Of course, this helps keep the files and properties organized and up-to-date—but it can also squash changes under certain circumstances.

The Problem Scenario

Let's say two Developers (A and B) are making updates in two different Sections. It's reasonable to expect there would be no conflicts, as the pertinent files are kept separate—save for the main project.yaml file, which will almost always conflict due to the dateModified value.

However: if Developer A pushes their work, and Developer B pulls it down (gracefully resolving any conflicts), Developer B can still clobber A's changes by immediately making a config update.

Here's a concrete example of this failure mode:

  1. 🟠 Developer A: Creates Field X
  2. 🟠 Developer A: Commits config changes and pushes to remote
  3. 🟢 Developer B: Pulls new commit(s) from remote
  4. 🟢 Developer B: Creates Field Y
  5. 🟢 Developer B: Commits config changes and pushes to remote
  6. 🟠 Developer A: Pulls new commit(s) from remote
  7. 🟠 Developer A: Observes Field X no longer exists. ⚠️

A Solution?

What's missing in the workflow above is between steps #3 and #4. Both Developers must always apply incoming Project Config changes before making any changes themselves.

The process (while a bit messy in reality) may look something like this:

  1. 🟠 Developer A: Creates Field X
  2. 🟠 Developer A: Commits config changes and pushes to remote
  3. 🟢 Developer B: Pulls new commit(s) from remote. If merge conflicts happen, that's OK—when isolated to project.yaml:
    • Pick either the current or incoming change
    • Run $ nitro craft project-config/touch to get a new dateModified, guaranteed to be ahead of both values that git knows about
    • 🚨 Run $ nitro craft project-config/apply to integrate Developer A's config changes
  4. 🟢 Developer B: Creates Field Y
  5. 🟢 Developer B: Commits config changes and pushes to remote
  6. 🟠 Developer A: Pulls new commit(s) from remote
    • Same (new) integration strategy applies as in step #3!

Developer A's Field X gets integrated, and Developer B's environment is completely aware of them prior to stacking any more changes on top.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment