Many parts of WordPress have been developed using GitHub as the central tool, along with countless plugins and themes and even the WordPress book. WordPress Deployment Part 5: Atomic Deployments In my last article, we looked at deploying WordPress using some different command line (CLI) tools. In this article, we’re going to look at how we can deploy WordPress using Git, both manually via the CLI and also automatically when you push code to your remote repository. Use Git & Composer.
Topics
- SVN Folders
- Best Practices
- Examples
- Notes
SVN, or Subversion, is a version control system similar to Git. It can be used via command line, or one of numerous GUI applications, such as Tortoise SVN, SmartSVN, and more. If you’re new to SVN, we recommend reviewing a comparison of SVN clients before deciding which is best for you.
This document is not a complete and robust explanation for using SVN, but more a quick primer to get started with plugins on WordPress.org. For more comprehensive documentation, see The SVN Book.
We’ll describe here some of the basics about using SVN as it relates to WordPress.org hosting. The basic concepts of SVN, and nearly all code repository services, remain the same.
For additional information, please see these documents:
Overview Overview
All your files will be centrally stored in the svn repository on our servers. From that repository, anyone can check out a copy of your plugin files onto their local machine, but, as a plugin author, only you have the authority to check in. That means you can make changes to the files, add new files, and delete files on your local machine and upload those changes back to the central server. It’s this process of checking in that updates both the files in the repository and also the information displayed in the WordPress.org Plugin Directory.
Subversion keeps track of all these changes so that you can go back and look at old versions or revisions later if you ever need to. In addition to remembering each individual revision, you can tell subversion to tag certain revisions of the repository for easy reference. Tags are great for labeling different releases of your plugin and are the only fully supported method of ensuring the correct versions are seen on WordPress.org and updated for users.
Your Account Your Account
Your account for SVN will be the same username (not the email) of the account you used when you submitted the plugin. This is the user ID you use for the WordPress forums as well.
Remember, capitalization matters — if your username is JaneDoe, then you must use the capital J and D or else SVN will fail. You can see the specific capitalization of your name at https://profiles.wordpress.org/me/profile/edit/group/1/
If you need to reset your password, go to login.wordpress.org
SVN Folders SVN Folders
There are three directories created by default in all SVN repositories.
The /branches/ directory is no longer created by default, as it was unused.
- Use
assets
for screenshots, plugin headers, and plugin icons. - Development work belongs in
trunk
. - Releases go in
tags
. - Divergent branches of code go into
branches
.
Trunk Trunk
Warning: Do not put your main plugin file in a subfolder of trunk, like /trunk/my-plugin/my-plugin.php
as that will break downloads. You may use subfolders for included files.
The /trunk
directory is where your plugin code should live. The trunk can be considered to be the latest and greatest code, however this is not necessarily the latest stable code. Trunk is for the development version. Hopefully, the code in trunk should always be working code, but it may be buggy from time to time because it’s not necessarily the “stable” version. For simple plugins, the trunk may be the only version of the code that exists, and that’s fine as well.
Even if you do your development work elsewhere (like a git repository), we recommend you keep the trunk folder up to date with your code for easy SVN compares.
Tags Tags
The /tags
directory is where you put versions of the plugin. You will use the same version numbers for the sub-directories here as you do for your plugin versioning. It is important that you always use tag folders and proper versioning to ensure your users get the correct code.
Version 1.0 of the plugin will be in /tags/1.0
, version 1.1 would be in /tags/1.1
, and so forth.
We strongly encourage the use of semantic software versioning.
Assets Assets
Assets is where your screenshots, header images, and plugin icons reside. It’s recommended but not required to put screenshot files in /assets
Branches Branches
The /branches/ directory is no longer created by default, as it was largely unused. This section can be considered deprecated and is available only for informational purposes.
The /branches
directory is a place that you can use to store branches of the plugin. Perhaps versions that are in development, or test code, etc.
The WordPress.org system does not use the branches directory for anything at all, it’s considered to be strictly for developers to use as they need it. As it is no longer created by default, you can ignore it as you do not need it any longer.
Best Practices Best Practices
In order to make your code the most accessible for other developers, the following practices are considered to be optimum.
Don’t use SVN for development Don’t use SVN for development
This is often confusing. Unlike GitHub, SVN is meant to be a release system, not a development system. You don’t need to commit and push every small change, and in fact doing so is detrimental to the system. Every time you push code to SVN, it rebuilds all your zip files for all versions in SVN. This is why sometimes your plugin updates don’t show for up to 6 hours. Instead, you should push one time, when you’re ready to go.
Use the trunk folder for code Use the trunk folder for code
Many people use trunk
as a placeholder. While it’s possible to simply update the readme.txt
file in trunk and put everything in tag folders, doing so makes it more difficult to compare any changes in your code. Instead, trunk should contain the latest version of your code, even if that version is a beta.
Always Tag Releases Always Tag Releases
While it’s possible to use trunk as a stable tag for plugins, this feature is not actually supported nor recommended. Instead, releases should be properly tagged an iterated. This will ensure full compatibility with any automatic updater, as well as allow for rollbacks should there be an issue with your code.
Create tags from trunk Create tags from trunk
Instead of pushing your code directly to a tag folder, you should edit the code in trunk, complete with the stable version in the readme, and then copy the code from trunk to the new tag.
Not only will this make it easier see any changes, you will be making smaller commits as SVN will only update the changed code. This will save you time and reduce potential errors (such as updating to the wrong stable tag and pushing bad code to users).
Don’t worry about the tag folder not existing for a short while. You can use svn cp
to copy trunk to the tag and then push them up to SVN at the same time.
If you are operating locally, then you can update trunk and create tags from it all in one go. Checkout the root of your repository, update the files in /trunk, then svn copy /trunk /tags/1.2.3
(or whatever the version number is) and then commit the whole thing in one go. SVN is a system based on differences, and as long as you use svn to do the copy operation, then it preserves history and makes everything easy for others to follow along with.
Wordpress Fitness Templates
Delete old versions Delete old versions
Since SVN is a release repository, it’s encouraged that you remove older versions of your code. This will make it faster when you need to checkout a fresh copy of SVN, but also will make new builds of your code faster. Keeping the last version of each major release is an easy way to keep the size down.
Examples Examples
Starting a New Plugin Starting a New Plugin
To start your plugin, you need to add the files you already have to your new SVN repository.
First create a local directory on your machine to house a copy of the SVN repository:
Next, check out the pre-built repository
In our example, subversion has added ( “A” for “add” ) all of the directories from the central SVN repository to your local copy.
To add your code, navigate into the my-local-dir
folder: $ cd my-local-dir
Now you can add your files to the trunk/
directory of your local copy of the repository using copy/paste commands via command line, or dragging and dropping. Whatever you’re comfortable with.
Warning: Do not put your main plugin file in a subfolder of trunk, like /trunk/my-plugin/my-plugin.php
as that will break downloads. You may use subfolders for included files.
Once your files are in the trunk folder, you must let subversion know you want to add those new files back into the central repository.
After you add all your files, you’ll check in the changes back to the central repository.
It’s required to include a commit message for all checkins.
If the commit fails because of ‘Access forbidden’ and you know you have commit access, add your username and password to the check-in command.
Remember your username is case sensitive.
Editing Existing Files Editing Existing Files
Once your plugin is in the directory, you will likely need to edit the code at some point.
First go into your your local copy of the repository and make sure it’s up to date.
In the above example, we’re all up to date. If there had been changes in the central repository, they would have been downloaded and merged into your local copy.
Now you can edit the file that needs changing using whatever editor you prefer.
If you’re not using an SVN GUI tool (like SubVersion or Coda) you can still check and see what’s different between your local copy and the central repository after you make changes. First we check the status of the local copy:
This tells us that our local trunk/my-plugin.php
is different from the copy we downloaded from the central repository ( “M” for “modified” ).
Let’s see what exactly has changed in that file, so we can check it over and make sure things look right.
If it all looks good then it’s time to check in those changes to the central repository.
And now you’ve successfully updated trunk.
“Tagging” New Versions “Tagging” New Versions
Each time you make a formal release of your plugin, you should tag a copy of that release’s code. This lets your users easily grab the latest (or an older) version, it lets you keep track of changes more easily, and lets the WordPress.org Plugin Directory know what version of your plugin it should tell people to download.
First copy your code to a subdirectory in the tags/
directory. For the sake of the WordPress.org plugin browser, the new subdirectory should always look like a version number. 2.0.1.3
is good. Cool hotness tag
is bad.
We want to use svn cp
instead of the regular cp
in order to take advantage of SVN’s features.
As always, check in the changes.
When tagging a new version, remember to update the Stable Tag
field in trunk/readme.txt
to the new version.
Congratulations! You’ve updated your code!
Notes Notes
Don’t put anything in SVN that you’re not willing and prepared to have deployed to everyone who uses your plugin. This includes vendor files, .gitignore
and everything else.
You also should never upload zip files. Like most code repository systems, SVN expects you to upload individual files.
See Also See Also
Strap in folks, this is a nerdy one. If you’re not already a little aware of the role of Git in your life, there’s a good chance that this article isn’t going to work for you. While I will make sure I anchor our conversation about Git Subtree’s use in my WordPress development with a little context of what Git is, it’ll be minimal. This is not a “Git” tutorial, it’s pretty explicitly a “git subtree” tutorial.
I don’t think git subtree
is right for everyone. I often don’t even think its right for me. But when certain realities our my work organizational structure and history demanded that I learn how to use it for WordPress development, I did. And so my goal here is to explain why Git Subtree was necessary for my (much loved) Git Push to WP Engine deployment system. And because that’s pretty closely a map off all the parts of git subtree
, I think this may help a few non-WordPress folks too. Lets get to it!
What’s Git?
In short, Git is a version control software. What that means is that I can use Git to figure out the history of my code, what its status was on a particular day, who was responsible to which changes on a specific line of code, etc.
We’ll assume that if you understand that, you’ll also familiar with the basic patterns of Git. That you understand you git pull
to receive changes to a local copy of a project, and git push
them share them with others on Github, Bitbucket, Gitlab, etc.
Why use distributed version control?
Strictly and importantly Git isn’t just “version control software,” it is distributed version control software. That’s got a lot of advantages over its centralized alternatives, like Subversion. By being distributed people can work asynchronously, and generally not have too many complication to fix simultaneous-file-change problems, aka “merge conflicts 👻.” (Don’t worry, they still happen though. And most developers fear them at least a little. Even me.)
Also by being distributed (and, relatedly, having cheap branching) Git makes a pretty good deployment tool. So a simple git push production master
works very well to put all the files for your WordPress site right on hosts that support it. As you get into more complex setups, this can fray on the edges. But for many WordPress sites it is way more than adequate.
Wordpress Gitignore
Why Git instead of SVN or Mercurial?
Why Git? I love touching on this just because git
annoys me. I feel like git
‘s CLI isn’t as well designed as others I’ve fiddled with from time-to-time, most relevantly Mercurial and Subversion.
But, for better worse, for complex (and simple) reasons, the world kind of all converged on Git as the distributed version control system of choice. The success of companies like Github and Gitlab owes everything to underlying success of Git vs its rivals. So partly we use Git because Git is good. Partly git
because to do anything else for version control these days is wacky and hard to justify. 🤪
Git Subtree vs Submodules
The primary problem we’re using Git subtrees for on this project is the same one that other people use “Git submodules” for. In both cases, the issue is “I have code I want to maintain in a separate Git repository. But I want to use that code in this project.” BTW: Composer is really the best-practice PHP answer for that problem, and one I continue to feel unsure quite how to mix into WordPress workflows best. (If you’ve got strong opinions on that and would like to write about them for WPShout, email “david” AT this domain. I’d love to publish an article or two on that. 🤓)
So to reuse code from a different project, we’ve got Subtrees and Submodules. If one of these is more popular, in my estimation it is surely Git Submodules. Here are the basic differences as I understand them:
- File control: A Git subtree pulls all files into the filesystem of your project’s Git repository. A Git submodule doesn’t add the “child project’s” files to your project’s history.
- History + Merging: with Git subtrees, you have commits explicitly merge in changes from the remote repository. In Submodules, those changes are tracked with a change to the
.gitmodules
file.
How I’m Using Git Subtree
So if Git submodules are more popular, why am I using subtrees? First: I’ve got a giant repo of all non-Core files in a WordPress site. Which means all the plugins, all the themes, and so effectively everything in wp-content
BUT the media files. And I’ve got a WordPress plugin that we’re maintaining independently because it’s also installed on a variety of other sites, other than this “monorepo.” So I’m using a Git subtree to track changes to the plugin in my “WordPress site” repository, and be able to git push
those changes to production.
WP Engine Allows Git Push Deploys with Subtree
In order to push my “sub-repository” to the WP Engine production server, I need its files to be reflected in the Git history. And to do that, I’ve been forced to use Git Subtree. My most recent use of Git Submodules was in the vague hope I could use them on this project. But then I realized that my valued Git push functionality (on WP Engine) required that I have a git subtree
instead. So that’s what I’ve got now.
To set this all up, there are really three basic steps:
1. Add Your “Sub-repository” as a Git Remote
First of all, we just want to save ourselves from needing to deal with a long Github/Gitlab/etc URL, so let’s define that remote as a branch to get a shorter name. In case it’s not obvious, in all the snippets that follow, you’ll be replacing MyGitSubRepo
with the actual “slug” you want to use for your project, capitalized and punctuated however you prefer. Similarly, you’ll customize my Github example URL. Anyway, command is:
2. Add that New Remote as a Subtree
Versionpress
Once we’ve got that remote, we need to tell Git where it should put our subtree’s files. Because my repository is essentially “a WordPress site” and my sub-repository is a WordPress plugin, that command looked like this for me:
What’s happening is that Git will then pull (and squash) the master
branch of your repository and make a commit to the current branch you’re on of the current state of that branch on your sub-repository.
Wordpress Github Pages
(Again, replace all MyGitSubRepo
with the real shorthand branch that matches how you think of your project.)
3. For future changes, fetch and pull your Git Subtree
The above will have initiated and pulled in all your files once. But chances are good that you’ve pursued this setup because you want to be able to pull changes from your Git sub-repository over time using the git subtree command. That’s basically done by (1) updating your local copy of the remote repository with a git fetch
and then (2) git subtree pull
ing in the changes, with a command very similar to the first pull:
Because I almost never need/want to run these command independent of each other, I have a little update-MyGitSubRepo.sh
script I can run to turn the two complex steps into a simple one-liner. But that’s by no means required, and a more extensive explanation of that isn’t really in the scope for this article.
A Gotcha That Gets Me A Lot
Wordpress Git Plugin
Doing all of the above will generally work fairly well for keeping your Git Subtree up to date for your WordPress plugin. There is a common issue that I have though: git subtree
requires that your local working copy be “clean.” By clean, I mean that it has no untracked-in-Git changes sitting around.
Making your Git repository “clean” before you update with Step 3 above isn’t too hard. It mostly means that your git status
should be blank. And 90% of the time, ensuring that before running works for me. If not, your command will fail with a Working tree has modifications. Cannot add.
response.
Sometimes I get that error because I forgot to clean my git status
. But I also sometimes get it even when I did. And that’s a frustrating and confusing error.
But, as I learned from a nice StackOverflow answer the solution here is a git command I didn’t know:
My quick summary of this command, having used it, is that it’s like a git status
with extra details. So often what I’ll find when running it is that an untracked file got updated, or something else that for various reasons git status
didn’t tell me about. Hopefully you won’t need it, but I also hope that having told you of it helps you out when you do.
Git Subtrees & WordPress: Branching Out in Git ;p
Wordpress Git Plugin
I don’t think most developers on most WordPress sites need to know about Git Subtrees. I think that most should use Git though 🤓
But I hope that by summarizing how I use Git Subtrees (and not Submodules) with WordPress I’ve given you a place to start when you finally have a situation that calls for you two maintain to independent WordPress code repositories for a single site. And if so, I hope you’ll have found this a bit less awkward to learn than I did. All the best!