Managing WordPress with Git

In addition to blogging, WordPress can be a great way to manage content for a basic website: what we in the biz like to call, a CMS. I’ve recently been building more websites using WordPress for the backend, and although it’s been relatively easy to manage content, it can be a pain to manage upgrades, plugins and theme customizations over FTP, or directly on the server.

Since I’ve had to do more wordpress development recently, the need to test and backup my customizations has increased. So I decided to set up a local mirror of my blog and put it under source control. I recently read an article entitled Using Git to manage a web site, which lists the steps needed to place your web content under git source control, and deploy that content to the production server over SSH. Using this system, you get two huge benefits just by learning a few git commands.

It would also be nice to be able to separate my customizations and content from official wordpress releases, and merge them in with each new release. A tutorial I found at wp.stackexchange.com (git by example – upgrade wordpress like a ninja) outlines the steps needed to mange this process.

I’ll show you how I use these two tutorials to manage this site. First, you want to set up your local git repository:
$ wget http://wordpress.org/wordpress-3.0.4.zip
$ unzip wordpress-3.0.4.zip
$ cd wordpress/
$ git init
$ git add .
$ git commit -m'check in initial 3.0.4 upstream'
$ git status

On my dev machine, I grab the same version of version that my blog is currently running on, initialize the git repo, and add/commit the files.

Next, we need to add all of our customizations (you can skip this step and the one after if starting a new blog or site from scratch) to a separate branch in git:
$ git branch mine
$ git checkout mine
$ rsync -cuvr MY_SERVER:MY_DOCUMENT_ROOT/ .
$ rm -rf stats error phpinfo.php
$ git status
$ git add .
$ git commit -m'added my themes, config and network patch'

Here, I create a branch called ‘mine’ and rsync the live site back to my local working folder. There’s some stuff I don’t need versioned, so I get rid of it. You can also add these files to a .gitignore file. If you don’t have rsync installed, you can ftp your customized WP files instead. If you are familiar with rsync, I reccomend adding ‘n’ to the flags so that you can preview what will be added to your pristine WP install.

Now we need to merge our changes and new files with the latest WP version:
$ git checkout master
$ cd ..
$ wget http://wordpress.org/wordpress-latest.zip
$ unzip wordpress-latest.zip
$ cd -
$ git status
$ git add .
$ git commit -m'check in initial 3.1 upstream'

Here, I go back to the master branch and extract the latest WP code over the existing files. Don’t worry about losing any data since git is tracking the changes.
$ git checkout mine
$ git rebase master
$ git reset wp-content/plugins/akismet/akismet.php
$ git checkout -f wp-content/plugins/akismet/akismet.php
$ git add .
$ git rebase --continue

In order to merge in he changes from the master branch, I rebase the code on the mine branch and handle the conflicts. The rebase command complained about a conflict in an Akismet plugin file which was changed between the base 3.0.4 version and the 3.1 upgrade. Since I didn’t care about losing that version (I must have updated it through the admin panel), I ended up resetting that file on the branch back to the 3.0.4 version and committing it.  rebase –continue finishes the merge of my customizations and the new 3.1 version in the master branch. I will repeat this process (the last two steps) every time I need to upgrade WP.

The next step is to automate the deployment of any updated or new files to the server. First, we’ll set up a remote repository that will mirror our local one:
$ mkdir WEBSITE.git && cd WEBSITE.git
$ git init --bare

Next, I need to add a script that will pull all updated files from git into the document root and restart the server:

$ vi WEBSITE.git/hooks/post-receive
#!/bin/sh
sudo chown -R MY_USERNAME MY_DOCUMENT_ROOT
GIT_WORK_TREE=MY_DOCUMENT_ROOT git checkout -f mine
sudo chown -R apache:www MY_DOCUMENT_ROOT
sudo /etc/init.d/nginx reload

(Replace everything in CAPS with your info except for GIT_WORK_TREE.)

In order for those sudo commands to run, I need to add these two lines to the bottom of my /etc/sudoers file (use visudo!) as root:
MY_USERNAME ALL=(ALL) NOPASSWD: /bin/chown
MY_USERNAME ALL=(ALL) NOPASSWD: /etc/init.d/nginx

Now, back on my local machine, I can add a remote mirror and deploy the files from my branch with  the git push command:

$ git remote add web ssh://MY_SERVER/home/MY_USERNAME/WEBSITE.git
$ git push web +mine:refs/heads/mine

After the initial push, you only need to type ‘git push web’  for subsequent updates.

Mirroring installations can have some pitfalls, such as accidentally deploying debugging code or special local settings. So I’ve added these lines of code to my wp-config.php file:
if (file_exists('dev_settings.php')) {
include('dev_settings.php');
} else {
$debug_on = false;
}
define( 'WP_DEBUG', $debug_on);

So I throw whatever custom settings into dev_settings.php and then I exclude that file from git so that it doesn’t get pushed up to the live server:
$ echo dev_settings.php >> .git/info/exclude
$ git status

And now you’re a bonafide WordPress-Git-Ninja!

I recommend excluding any user upload files from git and finding a way to back them up separately. The push process won’t remove anything from your doc root, so you can pick and choose which files you need under version control.

Please feel free to correct or suggest anything in the comments below.

Discussion

  1. There is a better way to do it, it’s using svn2git to clone svn repository and “mirror” it on a git repository, and for this new mirror repository to deploy on whatever installation you want. It simplify update process when needed as you only have to merge what’s changed

  2. Jerry Lee says:

    I love this way of managing my wordpress installations, I am wondering how hard it would be to add my plugins, themes, settings, etc. and use it for direct installation from my own GIT.

  3. Chris Meller says:

    Why would you want to restart the webserver every time you update the site’s files? That makes no sense at all…

    • Admin says:

      Because I’m an nginx newb and haven’t had time to figure out why it caches content so aggressively, although that’s the main reason why I’m using it (wordpress is running on apache). Restarting it seems to work.

  4. Casey says:

    I’ve been using git more and more for my python projects but was curious how wordpress devs use git in their theme dev and plugin dev workflow. Thanks for the insight.

  1. [...] Entrepreneur| Digital Marketer| Found… Here is an informative read on Managing WordPress with githttp://webxl.net/2011/03/10/mana… . Hope this helps.This answer .Please specify the necessary improvements. Edit Link Text Show [...]

Add a Comment

*