Managing Drupal 8 Config With git Within Teams With Multiple Developers
How do you manage syncing schema changes between developers in a repeatable, simple way?
In Drupal there's a system known as configuration management (export/import) for managing site configuration. However, you quickly realise it's not complete enough to use it alone to manage a multi developer scenario without some thought.
At the time of writing Drupal is celebrating it's 17th Birthday today, and is more powerful than ever, but with such power inevitably comes complexity and this shows in the time investment required to understand configuration management. It's not broken, it's simply complex.
Managing A Drupal 8 Database Changes Across Teams
- We need to version control the database across teams
- Deploy schema changes without fear, have ability for rollback
- Other projects have some interesting solutions which work very well
What are other projects doing to solve this?
We're used to working with 'migrations' using Laravel migrations and we've found it really simple to get a team of developers smoothly managing schema changes during development.
It essentially works in the following way:
- We use the console program
artisan
to generate a new migration- Artisan is just like Drush or Drupal Console, it generates boilerplate code for you
- Artisan expects a human readable name of the schem change made Timestamps schema change
- Artisan pre-fixes the migration with a time-stamp
- Artisan generates a boilerplate migration code (php) in a folder named
migrations
. - The developer writes an
up()
anddown()
function to perform the alteration (e.g. rename a table column) - The developer performs
php artisan migrate
and the outstanding migration is ran against the database.
- It's pushed to the repo, so all developers can use it seemlessly
The beauty of the up()
and down()
functions is that this allows the developer to rollback migrations forward or back schema changes as they wish. But most importantly it's simple and you can teach it in less than 30 minutes, and have a team pushing and pulling schema changes without fear of loosing config changes.
It's powerful and easy.
Most importantly Laravel Migrations is simple and you can teach it in less than 30 minutes. You can have a team pushing and pulling schema changes without fear of loosing config changes. Drupal 8 needs the convenience of Laravel's Migrations mixed with Drupal's powerful ecosystem because teams with less friction in development are happier, and less stressed, and keen to experiment.
It's a very convenient way of working, simple, and developers simply run git pull origin <branch-name>
and then run php artisan migrate
to perform any database schema updates they were behind on. There's also Doctrine Migrations which takes a different approach by making changes directly to your entity classes. asvae has written a comparison of Laravel & Doctrine migrations.
It's not that simple on Drupal. The configuration management system exports are not time stamped, nor are they migrations defined as code such as they are in Laravel (maybe this should be a thing?).
Instead, the result of a drupal config:export
are lots of .yml
files in your config/sync
directory which are taken out of the active config
in your database. This is a reflection of that database's active config- but it will blast over your current config (deleting your work) if you blindly run drupal config:import
on your local development environment. You need to preserve, merge and manage your configs using a combination of git and Drupal console. Luckily this can be turned into a repeatable pattern.
How to manage migrations in Drupal 8
So what can we do?
First, accept that Drupal is more complex that other systems. There are many abstractions which Drupal has built in which other systems simply have no concept of out of the box. This is similar to python's 'batteries included' motto. A good Drupal example are Bundles and Collections; sound complicated but really Drupal is helping you model your data (polymorphism in Drupal) before you knew you needed it; Drupal can often seem overly complex for these reasons, when actually it's well thought through.
Preserve Site Configuration Between Developers Using git & Drupal Console
- On your local environment make a change (e.g. add a description to a content type)
- Making a change like this would trigger a change to your
active config
which must be exported, committed and pushed to your remote (step 2)
- Making a change like this would trigger a change to your
-
Export your config (
vendor/bin/drupal config:export
)- Drupal console pulls your
active config
from the database, and serialises it into .yml in yourconfig/sync
directory.
- Drupal console pulls your
-
Review & add changes to config
git status
to see which files have changedgit diff <fileName>
to show the exact changes per file (if you want)git add <fileName>
to stage the changes for committing
-
Commit changes (
git add
)- This has the effect of preserving your config and giving you somthing to rollback to (using
git checkout <commit-hash>
) later if you need to recover from a mess.
- This has the effect of preserving your config and giving you somthing to rollback to (using
-
Pull from master (
git pull origin <branchName>
)- Assuming other developers have pushed to the remote, you pull changes down from your remote, which may contain schema alterations of their own. Git will attempt to merge these. If it fails, resolve the merge conflict it's not scary!
-
Review changes
-
composer install
Other Drupal modules may have been added to the project, so composer install is needed to fetch these. Otherwise you'll get the error "Unable to install the module since it doesn't exist", -
Import (if there were any) changes your fellow devs have made which includes yours automatically because of step 5 which preserves your changes. (
vendor/bin/drupal config:import
)- If there were no changes from your fellow developers you'll see the message "[OK] There are no changes to import.", otherwise, it will import both your changes and the rest from the remote.
-
Rebuild cache
vendor/bin/drupal cr all
-
Push to master (
git push origin master
) -
Switch to staging / production
-
git pull origin master
-
vendor/bin/drupal config:import
-
Rebuild cache
vendor/bin/drupal cr all
This is being expanded to include: -
What about preserving master site config changes
- e.g. If your client is allowed to alter the site name, this alters the site configuration and must be preserved
-
Using Git Hooks to automate the process