Git workflow for managing Drupal 8 configuration
The D8 way to replace "features-update" and "features-revert-all".
This is a preview of Nuvole's training at DrupalCon Amsterdam: An Effective Development Workflow in Drupal 8.
One of the new key features of Drupal 8 is the possibility to deal with configuration in code. Since configuration is now in text files, we want to put it under version control in Git to enjoy the many advantages this brings: comparing configuration states, keeping a history of configuration changes and even moving configuration between sites.
Setup
We will assume that you have a development version of Drupal 8, git and drush available on your system.
You can set up your Drupal git repository in several ways. One of them is outlined in Building a Drupal site with Git on drupal.org. The document is written for Drupal 7, but can easily be adapted for Drupal 8.
Another, probably simpler method is to simply download a Drupal 8 (alpha) release and initialise a new repository with it.
In either case you should copy example.gitignore
to .gitignore
and adapt it to your needs to prevent settings.php
and the files directory from being versioned.
The next step is to make sure that a configuration directory is versionable. By default Drupal 8 will place the staging directory under sites/default/files
and it is considered a good practice to not version that location, but an alternative location can easily be specified in settings.php
:
<span style="color: #000000"><span style="color: #0000BB"><?php<br>$config_directories</span><span style="color: #007700">[</span><span style="color: #DD0000">'staging'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'config/staging'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">?></span></span>
It is also possible and even advisable to specify a directory outside of the web root of course. In that case you would put the parent directory of your web root where drupal is under version control and use ../config/staging
. We will later see that it is also possible to add more directories and keys to the $config_directories
variable.
Because the configuration management of Drupal 8 only works between different instances of the same site, the different instances of the site need to be cloned. Cloning a Drupal 8 site is done the same way as cloning a Drupal 7 site. Just dump the database of the site to clone and import it in the other environment.
Development
After cloning your site you can go ahead and start configuring your site.
Once the part of the configuration you were working on is done the whole configuration of the site needs to be exported.
local$ drush config-export staging<br>The current contents of your export directory (config/staging) will be deleted. (y/n): y<br>Configuration successfully exported to config/staging.
Next, you need to merge the work of other developers. In some cases it may be enough to simply use git pull
, otherwise the configuration has to be merged after it has been committed:
-
Add all configuration to git and commit it.
-
Use git pull (or git fetch and git merge) and resolve any conflicts if necessary.
Git can merge changes in text files quite well, but git does not know about Drupal and its yaml format for configuration. It is, therefore, important to verify that the merged configuration makes sense and is valid. In most cases it will probably not be an issue and just work, but it is always better to be vigilant and be on the safe side. So, after merging, you should always run:
local$ drush config-import staging
If the import went smooth you can push the configuration to the remote repository. Otherwise the configuration needs to be fixed first.
Deployment
The simplest case is when the configuration on the production site has not been changed. There is an interesting Configuration Read-only mode module that can enforce this.
If the configuration did not change deploying the new configuration is simply:
remote$ git pull<br>remote$ drush config-import staging
If the configuration changes on the production site, it is best to frequently export the live configuration into a dedicated directory.
Add a new config directory in settings.php
:
<span style="color: #000000"><span style="color: #0000BB"><?php<br>$config_directories</span><span style="color: #007700">[</span><span style="color: #DD0000">'to_dev'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'config/to_dev'</span><span style="color: #007700">;<br></span><span style="color: #0000BB">?></span></span>
remote$ drush config-export to_dev -y
Add, commit and push it to the production branch so that the developers can deal with it and integrate the changes into the configuration which will be deployed next. Exporting the configuration into a dedicated directory rather than the staging directory avoids the danger that merge conflicts happen on the production site.
The deployment to the production site should be kept hassle free, so it should always be safe to pull from git and import the configuration without the risk of a conflict.
Important notes
It is important to first export the configuration changes and then pull changes from collaborators because the exporting action wipes the directory and re-populates it with the active configuration. Since everything is in git, you can recover from such a mistake without much difficulty but why make your life complicated.
Import the configuration before pushing it to the remote repository. Broken configuration breaks the site, be a nice co-worker.
Git doesn't solve everything! Imagine Alice and Bob start with the same site, it has one content type and among others an "attachment" field. Alice deletes the attachment field, exports the configuration and pushes it to git. In the meantime, Bob creates a new content type and adds the attachment field to it. Bob exports his configuration, merges Alice's configuration changes without a problem (the changes are separate files) and imports the merged configuration. The attentive reader sees where this leads. The commit of Alice deletes the field storage for the attachment field, but Bob added a field instance which depends on the field storage.
The exported configuration now contains a field instance that can't be imported.
At the time of writing, drush will signal a successful import but doesn't actually import it while the UI is more helpful and complains that the attachment field instance was not imported due to the missing field storage.
Tags: Drupal PlanetDrupal 8Code Driven Development