Large website projects involving multiple people in different roles face special challenges. The work needs to be coordinated and scheduled in such a way as to allow for parallel development of different parts of the project on different systems. As a consequence, sooner or later the different parts of the whole must be brought back together and integrated into the project’s main development trunk. Often, this process happens seamlessly; at other times, overlapping changes must be integrated manually.
In a Drupal 8 project, the Configuration Management module allows the website configuration files to be stored in a Git repository alongside the project code. As an added bonus, Git also provides features that facilitate distributed development, allowing work to be done on branches and merged together as required. When there are conflicts, external tools are available to visually present the conflicts to the user, making it easier to determine what happened in each instance.
Recently, the Drush project introduced a new command, config-merge
, that streamlines the tasks needed to manage the configuration workflow steps to fetch and merge changes from a remote Drupal site.
Image A shows a typical workflow for using Git to manage configuration changes between a local development server and a remote staging server. Releases are deployed to the staging server by first committing them to the master branch in Git, and then making a tag – <T1> in the diagram above – to keep track of what was deployed. Both code and configuration files are stored in Git. The deployment process on the staging server involves first checking out the tag being deployed and then running updatedb
and config-import
. Later, if configuration changes [a] and [b] are made on the staging server at the same time the developer is making configuration changes [u] and [v], these changes will need to be merged. This could, of course, be done manually, by running config-export
on both the staging and development server, committing them each on their own branch, and then using git fetch
followed by git merge
to combine them together into commit (M) on the development machine. Doing this all takes quite a few steps, though, particularly if using the configuration management admin interface in a web browser to export and download the configuration files. All of this can happen much more quickly with the Drush config-merge
command.
Drush's config-merge
tool is a lot like drush sql-sync
, which has saved Drupal developers countless hours by combining the sql-dump
, rsync
, and sql-import
operations to move a database from one Drupal site to another. config-merge
operates on the same principles, except that it uses config-export
, git fetch
and git merge
, and config-import
instead. To merge configuration from a Drupal site @dev with the configuration from a remote site @stage using Git, run:
drush @dev config-merge @stage –git
If there are no conflicts, then you will find the merged configuration imported on your development site; you are then ready to test it and deploy the combined changes back to the staging server. If there are conflicts, though, then config-merge
will launch a three-way merge tool and allow you to manually resolve the differences.
A three-way merge is so named because it works with three distinct revisions of each conflict:
- The revision that came from our repository, called "local" or "ours";
- The revision that came from the other repository, called "remote" or "theirs";
- The original state of the text, prior to either change being applied, called “base”.
All three of these revisions are shown together, side-by-side-by-side, and controls are provided to allow the user to select which changes to keep and which to discard. Usually, the user is also supplied with an editable fourth pane, where the final state of the file is shown, post-merge. In some cases, the final desired state requires that the "ours" and "theirs" revisions be combined or reordered in some way. In this event, the user may edit the text manually to fill in any gaps that the tool could not derive automatically.
Image B shows a screenshot of kdiff3, one popular three-way merge tool available for Linux and Mac OS.
It offers an example of where two different users have changed the same property – in this case, the region that the search block is displayed in. In the first of the three columns at the top, labeled the “Base” revision, we can see that the search block was originally in the sidebar_first region. On the local system, shown in the middle column, it was moved to the header region; at the same time, someone else moved search block to the sidebar_second region. A block cannot be placed in more than one region at once, so we are going to have to choose one value to keep. Kdiff3 provides three buttons, labeled “A”, “B”, and “C”, that can be used to select the text from the base, local, or remote revision, respectively, and copy it into the output pane on the bottom of the window.
This is just the beginning of what you can do with config-merge
and kdiff3
. For more details, see the Pantheon Systems GitHub repository, Drush Configuration Workflow.
This repository contains documentation that describes the workflow discussed here in greater depth, and also contains another workflow based on rsync, for use in instances where configuration changes are being made on a system that does not have access to commit to the central repository. There is even a handy quickstart script to help you get up and running quickly, should you not happen to have multiple copies of a Drupal site to work with.
With a little investment in time, you’ll be using config-merge
like a champ. In the long run, the time you save will astound you.
Image: "spot the differences" by Giulia van Pelt is licensed under CC BY-NC-ND 2.0