If you've got a plug-in hosted on the WordPress repository then you'll be fairly familiar with SVN and some of its commands. In this tutorial I'll show you how you can use Git, another version control system popularised by GitHub, to publish and maintain your plug-in.
What Is Git?
Git and SVN are both examples of Version Control Systems. WordPress' repository uses the latter (if you have a plug-in hosted on WordPress you'll be familiar with the 'check in' to make changes to this repository). They both allow you to track changes to your code, but there are big differences between them on how they do this.
SVN relies on a single "central repository" of the code (in our context: the WordPress plug-in repository). Every time you want to edit your plug-in, you need to make a local copy, make the changes, and then 'check in' these changes to the WordPress repository.
Git is a decentralized version control system. Rather than having just a local copy of your plug-in – you have an entire clone of your plug-in repository, complete with all its changes. The repository now exists in its own right on your computer. You can commit and track changes, revert changes or 'branch' your plug-in off in different directions all on your local computer. Only once you're happy to update your plug-in, do you then push your changes to your WordPress repository to make them public.
In this tutorial I'm assuming that you've got a plug-in hosted on the WordPress plug-in repository, or at least you've had your hosting request approved. If you're not sure how to get your plug-in hosted by WordPress, I suggest you read our article on how to publish to the WordPress plugin repository.
What Are the Advantages of Using Git Over SVN?
There are numerous arguments for and against using Git over SVN (as well as decentralized version control systems in general). Many of these stem from the fundamentally different ways Git and SVN track changes. An excellent, in depth analysis of Git and SVN can be found in CodeForest's Git vs SVN article, but for the WordPress developer:
- Off-line access – You can make and track commits on your own personal 'development repository'. Only when you want to make your changes public do you need access to the WordPress repository.
- Once you learn it, Git is much easier to use – This article will take you through the basic work-flow you'll need to make changes and update them on the repository. I've linked to some resources at the bottom that provide more detailed information on using Git.
- GitHub – Let's face it, this is how most of us have heard about Git. Its ability to encourage 'Social Coding' is made possible from the decentralized nature of Git. You can keep a copy of your plug-in on GitHub, encouraging the community to participate and make improvements or extensions that you can then include. Generally speaking it's a good idea to expose your plug-in to other developers.
- Easily 'branch off' your plug-in – You can create 'experimental' branches on your local copy to test possible new features, then if they work out, merge them back in when it's time to publish the next release of your plug-in.
One disadvantage of using Git, is getting it to play nice with an SVN repository. It's not actually that hard thanks to
git svn, and this article is here to guide you through it.
Step 1 Download Git
If you haven't already, you'll want to install Git. How to install Git is covered pretty well in the Git Community book and the Pro Git book (both excellent resources if you are new to Git). How to install Git will depend on your operating system, as will what GUI programs are available to you. In this tutorial I shall do everything through command line – and I encourage you to do likewise. At the end of the article I'll suggest some GUI programs you can use, but usually, I only use them to help visualize the branches of the repository.
Step 2 Clone Your Plug-in's WordPress Hosted Repository
As previously mentioned, with Git you don't 'check out' a copy of your plug-in – you clone the repository, complete with a history of the changes made, and all its branches and tags. Step 1 then is to clone your plug-in's WordPress hosted repository. As an example I'll be publishing a 'Post Type Archives Link' plug-in based on a previous tutorial. So (once you've been accepted onto the WordPress repository) open up your command line interface, and navigate to where you want to store the local version of your plug-in. I'm going to put it inside a folder called 'Plugins'. Once there we want to tell Git where to find our plug-in. At the time of writing there are nearly 20,000 plug-ins hosted in the WordPress repository, and over 500,000 revisions. We don't want to wait for Git to trawl through each of those to find our plug-in. So first of all, we find what revision our plug-in starts at (we want it's entire history). To do this we get the first log of your plug-in (when it was originally added to the repository):
svn log -r 1:HEAD --limit 1 http://plugins.svn.wordpress.org/your-plug-in-name
It will think for a while and then you should see something like this:
r520657 | plugin-master | 2012-03-19 03:56:31 +0000 (Mon, 19 Mar 2012) | 1 line
That first number, '520657' for my plug-in, is the first revision. We'll use it in the next command which tells Git to clone our plug-in's history. Replace XXXXXX with your revision number.
git svn clone -s -rXXXXXX --no-minimize-url http://plugins.svn.wordpress.org/your-plug-in-name cd your-plugin-name git svn fetch git svn rebase
-s' tells Git to expect the standard (Tag, Trunk, Branches) layout of an SVN repository. The '
--no-minimize-url' stops it looking outside of your plug-in folder. Make sure it is not missing. If you leave it out you could end up copying the entire WordPress plug-in repository. The
-rXXXXXX tells Git what revision to look for. If you leave that out Git will have search through the entire history of the repository. That's over 500,000 revisions. I left this out once and it took about two hours. With it in, it should only take a few minutes.
Once it's done, you should find that it's created a folder called 'your-plug-in-name' inside your 'Plugins' folder. Let's explore a bit. Navigate to the 'your-plug-in-name' folder and run a command to see what 'branches' exist:
git branch -a
This will list all branches, local and remote. The only local branch should be Master (the asterisk denotes that this is the branch you are on). The other branch(es) are the 'trunk' and, if you have any, a branch for each tag (SVN treats tags as branches, but Git is a bit cleverer than that).
Going to your 'local folder', 'plugins/your-plugin-name', you should see your plug-in files (if there were any). Before creating or editing any files in there, we are going to create a separate branch to work on.
Step 3 (Optional) Push to GitHub
One of the benefits of using Git is that you can easily maintain a version of your plug-in on GitHub. This makes your plug-in more accessible to other developers, who may suggest improvements or even make their own modifications which you could pull into your own repository. If you are already set up with GitHub, you may at this point want to push your plug-in onto your account. To do that, first create yourself a new repository on your GitHub account, and then add this as a remote branch to your local repository:
git remote add origin firstname.lastname@example.org:<your-user-name>/<your-repo-name>.git
'your-user-name' refers to your GitHub user name and 'your-repo-name' refers to the name of the repository you've created on GitHub. Then you just push your local repository:
git push origin master
Step 4 Editing Your Plug-in: Outline of Workflow
We shall create a new branch 'work'. It's inside this branch that we shall alter our plug-in, make changes and add features etc. This means our 'Master' branch is kept in its original state. This allows us to switch back to the Master branch, and branch off again. In particular, suppose a major bug is found in your plug-in while you are working on some new features in your 'work' branch. You can switch back to your your 'master' branch (which doesn't include any of the features you are currently working on), commit a fix for the bug and then push that to the WordPress repository. You can then switch back to your work branch and continue where you left off. (Note: Git doesn't create copies of your files – there will always be only one set of files in your local folder. What these files contain will depend on what branch you're on.)
In fact, it's a good idea to create a branch for each new feature you are adding to your plug-in. When you are finished you simply merge these back into the master branch. If this causes any 'conflicts', you'll be asked to resolve these manually.
First create a branch called 'work':
git branch work
Then 'check out' (go to) branch 'work':
git checkout work
A message will tell you that you've switched to the 'work' branch. Now use your favourite text editor to open up your plug-in's files in your local folder (or create them if there aren't any yet). Once you've made a few you may want to see what files you've changed. You do this with the simple command:
This will list changes of tracked and untracked files. There may be files you don't want Git to bother tracking (such as temporary files), but if you've added any new files to the folder you'll need to tell Git to track them. You can do this with the command:
git add <file-name>
I've created two files 'post-type-archive-links.php' and 'metabox.js' in my local folder, so I've added them to tell Git to track them. You must ensure that you are tracking your readme file.
You can also view the changes since your last commit (this is where a GUI program becomes very handy)
Once you want to commit the changes to your local repository:
git commit -a -m "Did abc to xyz"
providing a (detailed) message of the changes contained in the commit.
In the process of making changes you can (and should) commit as often as possible – but in a logical way, preferably with one commit for each 'thing' you do. You should make sure that there are no obvious errors in your commits either. 'Undoing' a commit is quick and painless: You do this by performing another commit that reverses the previous one:
git revert HEAD
(You'll be prompted for a message to describe this commit.)
Step 5 Committing to the WordPress Repository
Suppose you now are in a position where you want to push all your changes to the SVN repository. Before doing this, we need to bare something in mind. Git encourages you to commit often, and it's good practice to do so... for development. However, your WordPress plug-in repository is there for distribution. It doesn't need every single commit. In fact, it really doesn't want it either, as Otto (WordPress core contributor) warns:
"If I catch you at it [pushing each commit separately], then I will ban you from WordPress.org. The SVN only needs your final working version committed to it, not the entire history of the hundreds of changes you made using Git. Flatten your changes to a single commit."
To avoid this, when we're ready to push to the WordPress repository, we merge all the commits into one commit. There are a couple of ways of doing this. We shall merge (and simultaneously squash) our changes from our work branch into our master branch. Then all our changes appear is as one commit on the master branch. We then delete the work branch and push the master branch to our plug-in's SVN trunk.
First, we want to switch back to the Master branch:
git checkout master
Then squash and merge the work branch changes into the master:
git merge --squash work
If changes had been made to the master branch, there maybe conflicts in the merge. You'll be prompted to manually resolve these conflicts before the merge can complete. Once merged, commit the changes (this one commit will contain all the commits from our work branch):
git commit -a -m "Made changes a,b,c,d"
Finally, we delete the work branch
git branch -D work
If you have multiple branches you wish to merge in, then you can do this for each of them. There are alternative methods, which I won't cover, of flattening your history (such as interactive rebasing).
At this point you could, if you wanted, push your latest changes to your GitHub account:
git push -u origin master
To push to the WordPress repository, we first make sure our local repository is 'up to date':
git svn rebase
Git will then go and fetch your subversion repository and merge any changes there with the changes we've just made. Normally, there shouldn't be any changes to the WordPress repository, so you should see the message: Current branch master is up to date.
Now we can push our changes to the WordPress repository
git svn dcommit
Git may then prompt you for your WordPress.org credentials. Once entered your changes will be committed to the WordPress repository. Shortly you should receive an e-mail from the WordPress repository, informing you of the commits.
Step 6 Tagging a New Release
Currently, those changes will sit in the trunk. What if we want to tag a new release of our plug-in? When creating the next version for your plug-in you should have updated the ReadMe file, so that the stable tag points to your new version (say '2.0'). You should also have updated your plug-in's header information in your your-plug-in-name.php file. If you have forgotten to do this, just run through the above procedure, having made those changes.
Once your 'trunk' is fully up to date (including the latest version information), we simply then need to create the new tag in the WordPress repository:
git svn tag "2.0"
This copies everything in your trunk into tags/2.0 (what you normally achieve in SVN with
svn cp trunk tags/2.0).
If you wanted to tag the release in your local repository:
git tag -a 2.0 -m"Tagging 2.0"
Step 7 (Optional) Tagging a New Release on GitHub
Similar to what we did with the WordPress repository, make sure that our repositories agree, then push our changes and tags:
git pull --rebase origin master git push origin master git push origin --tags
Useful Resources for Git Commands
- Git Reference (Has a good section on 'How To Think Like Git')
- Git Community book
- Pro Git book
- Git Ready (Less of a guide, more a 'snippet' collection)
- SVN to Git crash course (helpful if you've used SVN for a while)
- Git Magic (a friendly introduction to Git)