Give me convenience
I used to track WordPress updates, plugin updates and my own manual site changes using git. I wrote a whole post about it. Either fortunately or unfortunately WordPress launched their update framework which is so much easier than what I was doing. I've given up on my old technique and moved to using WordPress' update mechanisms.
Of course what I really want is to be able to white a WordPress plugin that is notified any time an update occurs or a file update completes so that I can automatically track site changes in a SCM, but I don't think that's easy right now.
Tracking WordPress using Git
Update: I don't do this anymore.
I publish this blog through WordPress, for reasons I've outlined before. I run it with a custom theme and a bunch of plugins though, and I wanted a convenient way to keep my WordPress install up to date without having to reinstall everything all the time. I wanted source control for my blog install.
My first attempt involved mirroring WordPress SVN into a Git repository on github so that I had a Git version of the SVN tree (including branches, tags and every checkin separate) and seperate repository holding the changes I'd made for my web site. This eventually failed for two reasons, first the script I was using to mirror the SVN into Git had a habit of failing in bizarre ways and secondly having two repositories confused me.
Yesterday I decided to update my fairly outdated WordPress install, it had been missing security fixes for some time and was one minor version behind. Since tracking SVN hadn't worked I tried a simpler approach, a single Git repository containing a master branch that tracks releases and an ianloic.com branch to track the state of my site.
I set up master with a fresh download of WordPress 2.5 from wordpress.com, created my ianloic.com branch and applied the differences between my site and the 2.5 SVN tag (for all it's failures my old approach at least let me do this easily). I switched back to the master branch, deleted all the files (leaving my .git directory intact) and unpacked the new WordPress 2.6.1 tarball. I checked that in (to the master branch), tagged it 2.6.1 and then merged that into my ianloic.com branch. I pushed all that to github and then checked it out on my web server (at Dreamhost).
Normally with Git you're tracking just the master branch, but I want both master and ianloic.com branches to be tracked so my .git/config contains:
[remote "origin"] url = git@github.com:ianloic/wordpress.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [branch "ianloic.com"] remote = origin merge = refs/heads/ianloic.com
Now it's easy to track changes that I'm making to my site and update to the latest WordPress without risking losing anything. The process for updating to a new WordPress release is:
- on my laptop check out the master branch
- rm all the files except for .git from the directory
- unpack the new release into the directory
- git-add . — now git-status will indicate what has changed, been added or removed
- git-commit to check in the new version of wordpress
- git-tag versionnum to tag which version is currently in master
- git-checkout ianloic.com
- git-merge versionnum to merge the latest version into the site's branch
- git-push --all --tags to push all the branches and tags to github
- on my web server, git-pull to update to the latest release
I end up with a tree that looks like this:
How I set up gitweb
There don't seem to be any straight-forward documents on how to set up gitweb, the web interface to git repositories. Or at least I couldn't find any. After failing to get it working a couple of times and then succeeding a couple of times in different ways here's the recipe I came up with to get what you can see on http://git.ianloic.com/. What I have there is a bunch of git trees I'm following or working on. Perhaps not a bunch, but at least a few.
What you need:
- a recent git installed
- Apache
- the gitweb files (from your git distribution) somewhere in your web tree
Gitweb comes as part of recent git distributions in a gitweb/ directory. This needs to be accessible from the web. I just have a git checkout in my web area and use that. When you build git you can supply all kinds of defaults that are applied when gitweb.perl is transformed into gitweb.cgi. Compile-time configuration and since you can override all that in a config file I prefer to just use gitweb.perl directly. My config file gitweb-config.pl looks like this:
# where's the git binary?
$GIT = "/home/yakk/bin/git";
# where's our projects?
$projectroot = "/home/yakk/git.ianloic.com";
# what do we call our projects in the ui?
$home_link_str = "projects";
# where are the files we need for web display?
@stylesheets = ("/git/gitweb/gitweb.css");
$logo = "/git/gitweb/git-logo.png";
$favicon = "/git/gitweb/git-favicon.png";
# what do we call this site
$site_name = "Ian's git trees";
# these variables should be empty
$site_header = "";
$home_text = "";
$site_footer = "";
$projects_list = "";
$export_ok = "";
$strict_export = "";
Most of that should be fairly straight-forward. $GIT and $projectroot are local filesystem paths for the git binary and the directory that contains your git trees respectively. @stylesheets, $logo and $favicon are URLs. In my case I just use relative URLs. You can customize most of the other variables to tweak the text to display. We have values for all these because gitweb.perl contains junk defaults that need to be cleared.
I wrote a little wrapper CGI, invoke-gitweb.cgi to invoke gitweb.perl with an environment variable to tell it to load gitweb-config.pl:
#!/bin/sh GITWEB_CONFIG=gitweb-config.pl exec perl git/gitweb/gitweb.perl
Drop gitweb-config.pl and invoke-gitweb.cgi into the directory that contains your git trees. Make invoke-gitweb.cgi executable and make sure your Apache knows to execute *.cgi as cgi scripts.
If you load invoke-gitweb.cgi in your browser you should see gitweb in action! But your URLs are stupid.
Let's fix that with a .htaccess file:
RewriteEngine on RewriteRule ^$ /invoke-gitweb.cgi RewriteRule ^([?].*)$ /invoke-gitweb.cgi$1
This will make any requests for just the directory invoke gitweb and any requests starting with ? invoke gitweb with those arguments. It works pretty well for me.

