Before We Begin
Note: This tutorial assumes that you’re setting up a new Plugin in the WordPress.org repository, and that you are starting with a GitHub repository. If you have an existing Plugin in the WordPress.org repository and merely want to switch to managing it with Git/GitHub, then please see this awesome tutorial instead.
When you first request that your Plugin be added to the WordPress.org repository, one of the required fields is a URL to your plugin. As described by the form:
must be a link to a ZIP file of the working plugin that includes a completed readme.txt
For this reason (and the fact that I prefer working with Git), I like to start my Plugin development on GitHub. However, this leads to a few extra steps in getting the Plugin set up on the WordPress.org repository. The purpose of this turorial is to document these steps as much for myself as for anyone else who wants to do something similar.
Here’s an overview of the steps we’re going to take:
- Set up the Plugin on GitHub
- Submit the Plugin to the WordPress.org repository
- Wait. Probably for days.
- Sync up the Plugin from GitHub to the WordPress.org repository
Set up the Plugin on GitHub
If you already have a local Git Repository to push, skip to the “Existing Repository” section.
- Create a new repository on GitHub.
- Use the “README” link to create a new README file (there’s a reason not to do this when you initially create the repo… see the next step)
- Change the name of the
README.txt. This ensures that WordPress will recognize it in the Plugin Repository. If you don’t know where to start, use the sample readme.txt file
- Click the “New File” link to create the main file of your plugin. It is good practice to give it the same name as the overall repository name (e.g. sample-plugin/sample-plugin.php).
This is very easy 🙂
- Create a new repository on GitHub.
- Add the new repository as a remote to your local repository (make sure to use your repository name, not the sample below)
git remote add origin https://github.com/JPry/sample-plugin.git
- Push your code up to GitHub (this is assuming you’re working with the branch “master”).
git push --set-upstream origin master
Submit the Plugin to the WordPress.org repository
This part is fairly simple.
- In GitHub, copy the link to the “Download ZIP” button for your repository. I usually just right-click on the button and choose “Copy Link”
- Fill out the Add Your Plugin form on WordPress.org. Since you already have a README.txt file, this should be a matter of copy and paste. For the “Plugin URL” field of the form, use the link that you just copied from GitHub.
- Note: I’m not sure if this step is necessary. Delete your local repository. We’ll set it up again later.
Wait. Probably for Days
Seriously, just be patient. It could take a long time (a week or more) before the Plugin Review team is able to review and accept your plugin. It all depends on how many other plugins need to be reviewed ahead of you.
Sync up the Plugin from GitHub to the WordPress.org repository
Once your Plugin is reviewed and accepted, you will receive an email from WordPress.org with the link to your plugin. From here on out, we’ll use the link to the last plugin I set up this way:
There are a few sub-steps to this process, which I will flesh out even further:
- Connect to SVN, and link your local machine to the SVN repository
- Connect your local repository to GitHub
- Rebase your Git history onto SVN
- Push to SVN and Git
- Tag everything!
Connect to SVN
- First, we need to get the revision number of the first commit to the WordPress Subversion repository, because otherwise Git will try to go through all the 100000+ commits in order to find it:
svn log http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/
When I did this, I received the following output:
------------------------------------------------------------------------ r876816 | plugin-master | 2014-03-17 18:08:41 -0400 (Mon, 17 Mar 2014) | 1 line adding remove-wp-engine-404-for-bots by JPry ------------------------------------------------------------------------
- Use the revision ID (in my example,
r876816) to create a local Git Repository based on the SVN repository:
git svn clone --no-minimize-url -s -r876816 http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/
This generated the following output:
WARNING: --prefix is not given, defaulting to empty prefix. This is probably not what you want! In order to stay compatible with regular remote-tracking refs, provide a prefix like --prefix=origin/ (remember the trailing slash), which will cause the SVN-tracking refs to be placed at refs/remotes/origin/*. NOTE: In Git v2.0, the default prefix will change from empty to 'origin/'. Initialized empty Git repository in /Users/jeremypry/plugins/remove-wp-engine-404-for-bots/.git/ r876816 = 368bc048d6213a636054431e45bbc34ebadc6e20 (refs/remotes/trunk) Checked out HEAD: http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/trunk r876816
--no-minimize-urlflag is important, as it stops
git svn clonefrom moving into the base folder of the remote SVN repository and going through all plugins (see git-svn docs). We also use the
-sflag which is a shorthand way of setting trunk, tags, branches as the relative paths, which is the Subversion default (from git-svn docs).
In regards to the big WARNING message, it looks like it would be a good idea to include the
--prefixflag in the future. I would probably recommend doing something like
--prefix=svn/, so that we can still use the
originremote for GitHub later.
Move into the new directory
- Fetch any and all SVN revisions. Because this is for a new plugin, this shouldn’t take very long
git svn fetch --all
- Probably not necessary (for a new plugin) but we should ensure we’re up-to-date anyway:
git svn rebase
Connect your local repository to GitHub
- Add the GitHub repository as a remote.
git remote add origin https://github.com/JCPry/remove-wpengine-404.git
- Retrieve your commits from GitHub
git fetch origin
- Take a look at your branches, as we’ll need them in the next major step
git branch --all
I received this output:
* master remotes/origin/master remotes/trunk
Rebase your Git history onto SVN
Rebasing is something that seems pretty scary, but here we have a valid use for it: We want to set up the very first SVN revision as the beginning of our plugin history. The reason rebasing is required is because the Plugin creation in SVN took place after we created the GitHub repository. With that said, we’re ready to jump in! 🙂
- Run the rebase command:
git rebase --onto remotes/trunk --root remotes/origin/master
Here, you can see that I’m using the branch information from the previous section. The
--onto remotes/trunkflag is telling Git that I’m using the SVN trunk “branch” as the base, or beginning, of my history. The
--root remotes/origin/mastersection is specifying the exact branch we want to rebase. This is the history from GitHub.
I had 3 commits, so my output looked like this:
First, rewinding head to replay your work on top of it... Applying: Set up the Readme file Applying: Create the main plugin file Applying: Update minimum version
- See where we stand in the Git history:
Here’s my output:
Wed Mar 12 15:26:26 2014 -0400 382f7de (HEAD) Update minimum version [Jeremy Pry] Wed Mar 12 15:25:06 2014 -0400 9fa6aad Create the main plugin file [Jeremy Pry] Wed Mar 12 15:24:07 2014 -0400 88c72ca Set up the Readme file [Jeremy Pry] Mon Mar 17 22:08:41 2014 +0000 368bc04 (trunk, master) adding remove-wp-engine-404-for-bots by JPry [plugin-master]
What are we looking at? Well, basically you can see that
trunk(our SVN “branch”) and
masterare still back at the commit with ID
368bc04(the last one in the output above). We need to bring those up-to-date.
Create a new branch with the up-to-date history. I’m using the branch name
git checkout -b git-merge
- Switch mack to the
masterbranch, and merge in the new
git checkout master git merge git-merge
We’re almost there! Checking the status again with
git log, we can see that the
masterbranch is up-to-date, but
trunk(the SVN branch) is still behind:
Wed Mar 12 15:26:26 2014 -0400 d2bdb48 (HEAD, master, git-merge) Update minimum version [Jeremy Pry] Wed Mar 12 15:25:06 2014 -0400 36811a7 Create the main plugin file [Jeremy Pry] Wed Mar 12 15:24:07 2014 -0400 d85ad1f Set up the Readme file [Jeremy Pry] Mon Mar 17 22:08:41 2014 +0000 368bc04 (trunk) adding remove-wp-engine-404-for-bots by JPry [plugin-master]
- Before we go any further, we should delete the
git-mergebranch, since we’re done with it:
git branch -d git-merge
Push to SVN and Git
This section is easy, but the first step could take a bit of time (I’m not sure why…)
- Push the changes up to SVN
git svn dcommit
For me, when all was said and done the output looked like this:
Committing to http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/trunk ... A README.txt Committed r877638 A README.txt r877638 = 94682a77c937231cedd37fc11cfad5f588df1465 (refs/remotes/trunk) A remove-wpengine-404.php Committed r877639 A remove-wpengine-404.php r877639 = 30eddd8196c70af8a3bb5aa3f391fe2994be1d3c (refs/remotes/trunk) M README.txt Committed r877640 M README.txt r877640 = 0452d0393666971d6e3546a559535f775b05863f (refs/remotes/trunk) No changes between d2bdb48c8798c69b727b5c03a711b85f7f7396fb and refs/remotes/trunk Resetting to the latest refs/remotes/trunk
- Do a forced push to GitHub:
git push -f origin master
-fflag is necessary to force the push to go through. The reason is because of the
git rebasecommand that we used earlier. We have existing history on GitHub, and one of the side effects of rebasing is that all of the old history is removed, and replaced with new history. The forced push stops Git from complaining that the history no longer matches.
You already made this Plugin, so you should be ready to release it to the world! I’m tagging with version 1.0, but feel free to use a different version if applicable.
- Tag in Git
git tag 1.0
- Tag in SVN
git svn tag 1.0
This takes a lot longer… again, I’m not sure why, but I’m assuming it has to do with the processing that needs to be done by the SVN server.
The output should look something like this:
Copying http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/trunk at r877640 to http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/tags/1.0... Found possible branch point: http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/trunk => http://plugins.svn.wordpress.org/remove-wp-engine-404-for-bots/tags/1.0, 877640 Found branch parent: (refs/remotes/tags/1.0) 0452d0393666971d6e3546a559535f775b05863f Following parent with do_switch Successfully followed parent r877641 = df9c0f98857fbbf5e7f0f138a5bccdd67ff9d8b1 (refs/remotes/tags/1.0)
Working with the Plugin
Now let’s assume that we want to create a new release of the Plugin in order to invite the Plugin users to report bugs and get involved on GitHub. For that we need to edit the copy of
readme.txt and bump the version number of the plugin.
Once we have made the changes, we can check the status of our local Git repository:
Let’s commit the changes to our local repository:
git commit -am "Adding message about moving to GitHub, version bump"
Pushing Changes to GitHub
To publish our local commits to GitHub, we use
Pushing Changes to WordPress Subversion Repository
Once you have switched to using Git as your version control system, you should always use
git svn dcommit to publish changes to the SVN repository. Otherwise, you must run
git svn rebase every time before pushing changes to SVN in order to merge changes from the SVN repository into your local Git repo.
If you are not using
trunk as a release branch for your plugin, you may safely push all your Git changes to the WordPress repository without worrying about users getting update notices:
git svn dcommit
Tagging a release in Git is very simple:
git tag 1.0.1
To create an SVN tag, simply:
git svn tag 1.0.1
This will create
/tags/1.0.1 in the remote SVN repository and copy all the files from the remote
/trunk into that tag, so be sure to push all the latest code to
/trunk before creating an SVN tag.
Updating and Trakcing Plugin Assets
Assets folder in the WordPress SVN repository can be used for storing Plugin banners and screenshots. Make sure that the
/assets folder actually exists in your SVN repository before trying to fetch it. Open this in your web browser:
easy-digital-downloads is the slug of your plugin, and you should see the root folder of your Plugin SVN repository:
Revision 851441: /easy-digital-downloads .. 1.0.4/ assets/ branches/ tags/ trunk/
Notice that the
/assets folder is present.
Let’s track that folder as a seperate Git branch called
assets. Every time you need to update the cover image or screenshots you, simply checkout that branch, do the changes and publish it to SVN using the same old
git svn dcommit.
Add a new SVN remote called
git config --add svn-remote.assets.url http://plugins.svn.wordpress.org/easy-digital-downloads/assets
and set it to use the
assets branch on our remote SVN repository:
git config --add svn-remote.assets.fetch :refs/remotes/assets
This will have appended the following to our
[svn-remote "assets"] url = http://plugins.svn.wordpress.org/easy-digital-downloads/assets fetch = :refs/remotes/assets
which means that we can now fetch the
assets remote at its current HEAD:
git svn fetch -r HEAD assets
and switch to it using:
git checkout remotes/assets Note: checking out 'remotes/assets'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b new_branch_name HEAD is now at 7e5b727... Updated banner image
Let’s create a local branch called
assets to track this remote:
git checkout -b assets
Now you can add and modify Plugin assets, commit the changes and then publish the changes to the SVN, using:
git svn dcommit
Converting SVN Folders into Git Branches and Tags
In the list of newly created branches we see that all SVN tags have been turned into regular Git branches. Here is a simple script to convert those tag branches into proper Git tags:
git for-each-ref refs/remotes/tags | cut -d / -f 4- | grep -v @ | while read tagname; do git tag "$tagname" "tags/$tagname"; git branch -r -d "tags/$tagname"; done
And we can do the same for all other references under
refs/remotes — turn them into Git branches like so:
git for-each-ref refs/remotes | cut -d / -f 3- | grep -v @ | while read branchname; do git branch "$branchname" "refs/remotes/$branchname"; git branch -r -d "$branchname"; done