After getting my server environment set up I needed to come up with a plan for getting the code off of my live site and on my development box. In addition, I want to be able to track the changes I make so I know what needs to be uploaded back to the server, and so I can feel free to experiment without worrying about keeping track of every little thing I change. That of course means I need a version control system. The most common version control system in open source projects these days is git, and that’s what I’ve decided to use.
When I listed my requirements in Part 1 there were a few that are probably a little unusual. Given the small size and low traffic of my site I will in all likelihood continue to make the occasional change to the live server directly. I also plan on keeping WordPress’s auto-update feature on, so the server will be updating itself from time to time.
The most unusual however is that my shared hosting provider doesn’t allow git to be installed on its shared hosting plans. Usually the way a git workflow would go is that I would create a git repository on the server. Locally I would clone that repository, and when it was time to update the server I would execute the ‘git push’ command to push the changes. There aren’t any good ways to get around this shortcoming of my hosting plan.
With no git on the server, I instead decided to use SFTP , the secure version of the file transfer protocol. As a SFTP client I’m using the program Beyond Compare 3, which I already owned. Unfortunately it is a bit pricey at $50 (only the Pro version has SFTP support). Another good alternative is the completely free WinSCP. The interface isn’t as slick and you might have to jump through a few more hoops to do certain things but it is a great program overall.
I also needed to develop a workflow for how I will use git once I have the code on my local box. I spent a lot of time messing around with git and reading the online git book. What I finally came up with was can be seen in the following diagram.
I’m going to assume you’re either familiar with git or have done some heavy reading in the book as well.
The Master Branch
This is the default branch that git creates when you first commit files, and if you don’t commit anything it won’t create it, so I just added a .gitignore file. This branch is intended to always reflect the state of the live site, with the only additions being any code about to be uploaded to the live site.
$ git init # create a .gitignore to hide files from git # for WordPress and Eclipse IDE added these lines: #.buildpath (eclipse) #.project (eclipse) #.settings/ (eclipse) #wp-config.php (WP) #wp-config.php.bak (WP) #.htaccess (Apache) #.htaccess.original (Apache) #*.log (WP) #error_log (WP) $ git add . $ git commit -m 'added a .gitignore file'
Next I created a new branch with
$ git checkout -b live-sync. This is the branch where I will do all the uploading and downloading from the live site. I’ve just created it but, in the future, after checking out live-sync, and before syncing with the server, I’ll run
$ git reset --hard master, to have the directory reflect what the server looked like last time plus any new additions.
Now I can log into the server and use the directory comparison feature of Beyond Compare, or WinSCP, to get the local and remote directories in sync. Beyond Compare allows me to tell it to exclude certain folders. (I’m not sure if WinSCP can do that). I need to tell it to ignore the same stuff git is ignoring so I don’t accidentally download something from the server I’m not supposed to (or, worse, vice-versa).
After downloading the site its time to check the code into the repository and then sync up master with the current state of the server.
#Still on the live-sync branch $ git add . $ git commit -m 'download live site on 20130328-1200' $ git checkout master $ git merge live-sync
Managing local configuration files can be a challenge for most version control systems, git included. Applications tend to have some kind of configuration file, and the settings for a local machine are going to differ from the live application. The configuration files might also contain sensitive information like database passwords. There must be a hundred different threads on the internet asking how to handle this situation.
There are a handful of different suggestions for what to do but none of them are particularly good. There are usually corner cases where the solution doesn’t do what you want it to. WordPress has only has two configuration files, wp-config.php and .htaccess, so my approach is just to add them to the .gitignore file and make sure to never transfer them by FTP. More complicated apps might require another solution but, for simple setups, don’t bother.
The most common suggestion for handling configuration files, by far, doesn’t work. This is the suggestion to create a .gitattributes file where you can specify special settings for individual files, or file patterns. One such setting is the merge attribute. You can add something like “*.txt merge=ours” to .gitattributes.
It looks like this tells git to always keep the version of the file the branch already has. The problem is, it only uses this merge strategy if there is a conflict, i.e. if both files have been changed since they branched off from each other. If you branch a file, change it in the new branch, but leave it the same in the original branch, there is no conflict and the merge strategy is not invoked!
There is an option to the merge command “git merge -s ours otherbranch” command. This works but it ignores everything, not just specific files.
Merge strategies are not a viable option for keeping config files different in different branches. If you must do something more fancy than just ignoring the config files use smudge and clean filters.
With WordPress there is more to configuration than just the configuration files. There is also the database to worry about. The URLs on your local machine are going to be different from the ones on the live machine. To get the database copied to the local machine I use a plugin called Migrate DB . It handles changing the URLs and even changes them in the serialized data streams WordPress stores options in.
Even with that though, there are some things that I want to change on the local machine. For example, I want to change the theme color of the admin screens so I can easily tell if I’m on the live machine or the development one. I have written a simple WordPress plugin that lets me do stuff like that. (I’ll post about it later). The problem is, I don’t want it showing up on the other branches. Mainly because I don’t want to have to worry about constantly ignoring it when I merge into master. I do however want to track changes to the plugin and any other configuration scripts I may write.
Therefore, the policy for this branch is simple. Never merge it into anything. That way I can write and track utilities here to help configure my local copy of the site, and when I switch branches git will remove them from the file system.
The Dev Branch and Its Children
The dev branch is intended to be a buffer between the development of features and the master branch. All the real work happens in branches that come off of dev. There is a try-plugins branch for, sensibly enough, trying out plugins. Feature branches are for writing new code.
Newly developed features are merged into dev when they are ready for prime time. This branch is basically a combination of the development and release candidate branches of Vincent Driessen’s branching model. Merges on dev should be done with full history (i.e. don’t use the –squash option). Merging into master on the other hand should use the –squash option so that all the messy history is kept on the dev branches, and I can just see what new features have been added.
This setup is almost certainly a little overkill for a one man “team” working on a small site, but devising it prodded me to learn a little about git, so it is worth it. I do think it will help me avoid making certain kinds of blunders when updating the site, and I’m already using it to explore plugin development with no worries.