You are here
Home ›Drupal Release Management with Drush and Git
A good software engineer will tell you that you really should use some kind of version control when developing your software, and good Drupal developers will tell you that Drush is fantastic for downloading module updates and general maintenance of your Drupal install. But how do you make your Drush and Version Control play nicely together? This article looks at using Drush together with Git to manage updates to your production Drupal site. This builds on Simon Hobbs’ extremely helpful article on setting up Drush Aliases. It also assumes that you’ve set up Git on both your development and production servers1, and have set up SSH keys2 to make life easier.
Introduction
Two of the most valuable lessons I ever learned as a web developer, I picked up at a Web Directions South workshop. The lessons were:
- Only ever make updates to your production sever through your version control tool; and
- Always have a single line command make this happen.
The advantage of the first rule is that if everything goes pear-shaped, you should be able to just roll everything back to the last revision and it will all be magically OK again (at least, that’s the theory). The advantage of the second rule is that it makes it much, much less tempting to just log into the production server and make a few small changes here and there. Having a single line command means that it becomes easier to do things the right way than it does to make changes to the live server.
These rules have saved my bacon quite a number of times, but when it comes to Drupal websites, it’s not quite that simple. The thing about Drupal is that the line between code that goes in files and content that goes in the database can get a little blurry. So when we update a third-party module for instance, we always run the update.php command so that the module can make sure the database is all OK. This is fine, except that our version control system doesn’t know about the database, so unless we’re careful things can get a bit messy.
Imagine for a moment that an update has been released for the Views module. You’ve installed it on your local development server, checked that everything still works OK, committed the changes into Git, and now you’re ready to make it live. If we’re going to use a single-line release script, we want it to follow all the standard, recommended Drupal upgrade steps that we all know we should follow:
- Back up the database
- Back up the code
- Put the site into maintenance mode
- Move the updated code into place
- Run the appropriate
update.phpscripts
Now, Git should take care of items 2 and 5 for us, and if you’ve followed Simon’s instructions for setting up Drush aliases, items 1, 3 and 5 are a piece of cake. Let’s go through them one by one.
Backing up the database
If we’ve set up our site aliases right, getting the database into a file with Drush is really simple. We don’t even have to log in to the production server.
# drush @prod sql-dump --ordered-dump > `drush dd @prod:%dump`
And committting it with Git is fairly straightforward too:
# git commit -a -m "Backup of the production database before performing an update"
At this point I usually also commit any user-uploaded files to the repository too. Some people set Git to ignore the sites/default/files directory, but I want to be able to restore my website to its exact state just before I updated the code, and this includes user-uploaded files. The only trouble is, the files need to be committed on the live site, because that’s where they are. So, we will need to log into the remote server and commit the files there:
# ssh user@remote.host -C \
"cd /path/to/web/root; git commit -m 'Backup of user files before code update' sites/default/files;"
Backing up the code
Now, in theory, our Git repository should have a complete history of our code, so all we need to do is commit our changes and make sure they’re all merged into the master branch. Once we’ve done this, we’re ready to put the site into maintenance mode.
Putting the site into maintenance mode
Again, if we’ve set up our Drush site aliases, putting the production server into maintenance mode can be done straight from our local command line. For Drupal 6:
# drush @prod vset --always-set site_offline 1
And for Drupal 7:
# drush @prod vset --always-set maintenance_mode 1
Moving updated code into place
Now that everything has been backed up and the site is in maintenance mode, we can move our code into place. Fortunately the Git push command makes this really easy, although with one small caveat. Git won’t let you push straight from your local repository to a remote repository if the remote repository is checked out. So, what I do is keep the production website on a branch called ‘live’ so I can push to the master branch. I’m no Git expert, so there may be much better ways of handling this out there, but it works for me. This is achieved by:
# git push
# ssh user@remote.host -C "cd /path/to/web/root; git merge master"
Running the update script
Again with Drush installed, this step is easy.
# drush @prod updatedb
Put the site back online
Finally, we put the site back online and, in theory, everything should be running smoothly.
# drush @prod vset --always-set site_offline 1
# drush @prod vset --always-set maintenance_mode 1
Putting it all together
Now, I said previously that you should be able to do all this with a single line command. So, what I did was write a PHP script that does all of this for me. To make it work though, I’ve had to add an extra key to my aliases.drushrc.php file. I’ve added a git-branch entry that looks something like this:
'git-branch' => 'website-live'
If you’re interested, you can download my release script below.
Update: If you’re interested in doing this in a multisite environment, I’ve written about multisite setups in another article
-
I found Joe Maller’s guide on installing Git on shared hosting really, really helpful for this. ↩
-
If you need a quick reminder on how to do this, try Matt Wynne’s quick guide. If you’re on Windows using Putty, you can find slightly more detailed instructions for SSH keys with Putty on Daily Iteration ↩


Comments
What I do with git for pushing to a live site is this:
Live site has two branches: master and develop. Locally I have the same two branches. I work on the develop branch. To get my updates to the live server, I do:
That’s essentially:
Then on the server, I keep master checked out, and do a:
I’m not sure if one way is more standard than the other, but it seems like a good idea to have master checked out on the server to me. The important thing of course is that everyone who uses your server knows the routine.
Cheers!
Hi there,
I got an error when i run the command
# drush @prod sql-dump --ordered-dump > `drush dd @prod:%dump`
I believe the error is because my drush alias file is a bit different from yours.
Would you mind to send to me a sample of an alias file that would make the command above work?
cheers,
Thanks for your comment @iurisampaio. If you could let us know a little bit more about your particular issue, it might help diagnose your problem a little quicker. In particular:
In the meantime, the following snippet from Simon Hobbs' article might help. Your setup may differ depending on whether you want to store the dump on the remote server or the local server:
Hi there,
Thanks for the feedback!
It is an uncommon error. The prompt gets strange and i can't properly type the write the passphrase to connect to the remote server. After pressing ctr+c 2 or 3 times, the prompt apparently gets in shape and i can type the passphrase. But the message i get is always:
"Drush command terminated abnormally due to an unrecoverable error."
Which it is totally expected. Because the passphrase wasn't well typed. (trash gets in the buffer when i type ctr+c). The issue is: the prompt crashes when i run the command
# drush @prod sql-dump --ordered-dump > `drush dd @prod:%dump`
I am installed the latest version: drush-all-versions-4.2.tar.gz from http://drupal.org/project/drush#downloads
my alias file is
<?php
$aliases['dev'] = array(
'uri' => 'dev.iurix.br',
'root' => '/var/www/iurix',
'path-aliases' => array(
'%drush' => '/usr/local/src/drush',
'%drush-script' => '/usr/local/src/drush/drush',
'%files' => '/var/www/iurix',
'%dump' => '/var/www/iurix/database-backup/iurix-dev.sql', // Arbitrary location for temp files
),
'command-specific' => array (
'rsync' => array (
'simulate' => '0',
'mode' => 'rlptDz',
),
),
);
$aliases['prod'] = array(
'uri' => 'prod.iurix.br',
'root' => '/var/www/iurix',
'db-url' => 'mysqli://iurix:iurix@123@prod.iurix.br:4487/iurix',
'remote-host' => 'prod.iurix.br',
'remote-user' => 'iurix',
'path-aliases' => array(
'%files' => '/var/www/iurix',
'%dump' => '/var/www/iurix/database-backup/iurix-prod-'. date('Y-m-d') . '.sql',
),
'command-specific' => array (
'sql-sync' => array (
'simulate' => '0',
),
'rsync' => array (
'simulate' => '0',
// 'ssh-options' => '-p9999',
),
),
);
?>
By the way i put simulate to 0 in order to the rsync and sql-sync actually take effect and do the job.
When i had it turned to 1, it just executed the command but no files were synchronized and no dumps were done.
Is that correct?
Since you’re using Drush 4.0, I’d first of all suggest trying the new
sql-dumpsyntax:Hopefully, that might help. Also, I usually try and use key pairs with
gitcommands, because passwords can get mangled when you’re moving between shells, php and ssh.Thank you ever so much, I'm just learning my way around version control and this was exactly what I was looking for.
Alan
Hrm. So you're not using git for drupal core version control? What about for modules? Is it possible to do both of those things while using git as a staging manager?
Thanks for the comment Naught. In response to your question, the switch to Git for Drupal.org had not yet happened at the time this article was written, so using Git for core and module updates wasn't an option. It is possible to do both those things while using Git as a staging manager, but it makes things a little more complicated. There is, however, a project to help with exactly this. It is called DOG (Drupal on Git), and you can find it at: http://drupal.org/project/dog Reading the introductory post may help get the idea better though.
Add new comment