Key takeaways from this article:
- WordPress.org uses SVN — not Git. If you come from any modern development workflow, nobody explains this transition clearly. This article does.
- You do not need a paid SVN GUI client. A single shell script handles the entire Git-to-SVN sync from Terminal — the same script WhoKnew uses in production for every plugin release.
- The version sync rule is the #1 mistake new plugin developers make. Three things must match exactly: your PHP file header, your readme.txt stable tag, and your SVN tag. If any one of them is wrong, WordPress.org shows the wrong version or doesn’t update at all.
- The script handles new files, deleted files, and dev-file exclusions automatically. You change three variables, run it, review what it staged, then tag and commit.
- After committing, WordPress.org typically reflects the update within 15–30 minutes. The plugin page, download count, and version badge all update without any action on your part.
You got the approval email. Congratulations — your plugin is live on WordPress.org.
Now what?
If you’ve spent any time with Git, npm, PyPI, or any other modern version control or package distribution system, the answer to that question is not obvious. WordPress.org uses SVN — Subversion — a version control system that predates Git by about five years and operates on a completely different mental model. Most tutorials either assume you already know SVN, point you to a paid GUI client, or gloss over the details that actually matter when something goes wrong.
This article skips all of that. It explains the workflow clearly, gives you a production-ready shell script that handles the Git-to-SVN bridge automatically, and walks you through your first deployment step by step. No SVN app required. No paid tools. Just Terminal.
Why WordPress.org Uses SVN (The Short Version)
WordPress.org was built in an era when SVN was the standard. The plugin directory is hosted on an SVN repository, and that is not going to change — the directory has over 60,000 plugins and the infrastructure is deeply tied to the SVN workflow. Understanding this is not a complaint, it’s just context. You are bridging two version control systems: Git for your local development, SVN for distribution to WordPress.org.
The mental model shift is straightforward:
- In Git, you have branches. In SVN, you have
trunk— that’s your main working copy, equivalent to your main branch. - In Git, you tag releases. In SVN, you copy
trunkinto atags/X.X.Xfolder — that’s how WordPress.org knows a release exists. - In Git,
.gitignorecontrols what gets committed. In this workflow, anrsyncexclude list controls what gets synced to SVN — keeping dev files off WordPress.org entirely.
That’s the whole model. Once those three mappings click, the rest is just mechanics.

One-Time Setup: Checking Out Your SVN Repository
Before the script can do anything, you need a local copy of your plugin’s SVN repository. You do this once per plugin — never again after that.
Find your SVN URL on WordPress.org. It follows this pattern:
Replace your-plugin-slug with the slug that appears in your WordPress.org plugin URL. Then check it out locally:
This creates a local folder at ~/wordpress-svn/your-plugin-slug containing three subdirectories:
trunk/— your current working plugin files. This is what gets deployed.tags/— one subfolder per release version. WordPress.org reads these to serve downloads.assets/— your plugin’s listing page visuals: icon, banner, screenshots. This folder does not affect the plugin code itself.
If you’re checking out a brand new plugin, all three folders will be empty. If you’re picking up an existing plugin, you’ll see your previous releases in tags/ and your current code in trunk/.
On macOS: brew install subversion
On Ubuntu/Debian: sudo apt install subversion
On Windows (WSL): sudo apt install subversion inside your WSL terminal. If using Git Bash instead of WSL, you’ll need to install SVN separately — WSL is the cleaner path.
The Script
The full script lives on GitHub at github.com/WhoKnewIO/wordpress-svn-deploy. Download or clone it from there — the README covers setup in condensed form and this article is the full walkthrough.
The script does five things in sequence:
- Uses
rsyncto copy your Git repo into SVNtrunk/, excluding files that should never reach WordPress.org - Detects any new files and runs
svn addon them - Detects any deleted files and runs
svn deleteon them - Shows you a status summary of everything staged
- Stops — and waits for you to tag and commit manually
That last point matters. The script does not commit automatically. It stages everything and shows you what’s about to go to WordPress.org, then hands control back to you. That’s intentional — a bad commit to SVN is harder to undo than a bad Git commit, and the review step takes ten seconds.
To configure the script, edit the three variables at the top:
PLUGIN_NAME=“Your Plugin Display Name”
GIT_DIR=“/full/path/to/your/local/git/repo”
PLUGIN_SLUG=“your-plugin-slug”
# ──────────────────────────────────────────────────────────────
PLUGIN_NAME is just a label used in the script’s output — it doesn’t affect anything on WordPress.org. GIT_DIR is the absolute path to your local plugin repo. PLUGIN_SLUG must match exactly what’s in your WordPress.org URL and SVN checkout path.
What Gets Excluded
The rsync command in the script excludes a standard set of files that should never reach WordPress.org:
- Git internals:
.git/,.gitignore,.gitattributes,.github/ - Dependency folders:
node_modules/,vendor/ - Test suites:
tests/,phpunit.xml,phpcs.xml - Build tooling:
webpack.config.js,package.json,package-lock.json,composer.json,composer.lock - OS noise:
.DS_Store,Thumbs.db,desktop.ini - The deploy script itself
If you have project-specific files that shouldn’t reach WordPress.org — a config.local.php, a private key file, a build artifacts folder — add them to the --exclude list in the script before your first run.

Your First Deployment: Step by Step
With the three variables set and your SVN checkout in place, here’s what a full deployment looks like from start to finish.
- 1
Run the script. From Terminal:
./deploy-plugin-svn.sh— if you get a permissions error, runchmod +x deploy-plugin-svn.shfirst. The script will print each step as it runs. Watch for any errors in the rsync output — these are usually path problems inGIT_DIR. - 2
Review the SVN status. The script ends by printing
svn statusoutput. Lines starting withAare new files being added. Lines starting withDare files being deleted. Lines starting withMare modified files. Scan this list — if something looks wrong (a file you didn’t expect to see, a deletion you didn’t intend), stop here and investigate before committing. - 3
Verify your version numbers before committing. This is the step most developers skip and then regret. See the version sync rule below — read it before continuing.
- 4
Tag the release. From inside your SVN checkout directory:
svn copy trunk/ tags/X.X.X— replaceX.X.Xwith your version number. This is what tells WordPress.org a new release exists. Without the tag, the update won’t show up for existing users. - 5
Commit.
svn commit -m "Release version X.X.X" --username your-wordpress-org-username— SVN will prompt for your WordPress.org password. Use your WordPress.org account credentials, not your hosting credentials. The commit uploads everything to WordPress.org.
The Version Sync Rule
This is the single most common mistake plugin developers make on their first few releases. Three things must match exactly — if any one of them is wrong, WordPress.org either serves the wrong version or doesn’t register the update at all.
| Location | What to check | Example |
|---|---|---|
| Main plugin PHP file | Version: in the file header comment | Version: 1.2.0 |
| readme.txt | Stable tag: header | Stable tag: 1.2.0 |
| SVN tags folder | The folder you create with svn copy | tags/1.2.0/ |
All three must be identical. Check them before every commit — it takes ten seconds and saves you from pushing a release that shows the wrong version number to every existing user of your plugin.
Updating the PHP header but forgetting readme.txt. WordPress.org reads the stable tag from readme.txt — if it doesn’t match, the download still serves the old version.
Tagging as 1.2.0 but readme.txt says trunk. Setting Stable tag: trunk in readme.txt works during development but should be changed to the actual version number before release.
Inconsistent formatting. Version: 1.2 and Stable tag: 1.2.0 are treated as different versions. Pick a format (major.minor.patch is standard) and use it consistently everywhere.
After You Commit: What to Expect
SVN commits to WordPress.org are not instant but they’re not slow either. In most cases:
- Plugin page version number updates: 15–30 minutes
- Download served to new installs: usually within the same window
- Update notification pushed to existing installs: WordPress checks for updates periodically — sites will see the update prompt within a few hours, sometimes faster
If your update isn’t showing after an hour, check two things first: confirm the SVN tag exists (svn list https://plugins.svn.wordpress.org/your-plugin-slug/tags/) and confirm the stable tag in your committed readme.txt matches the tag name exactly.
Getting the plugin deployed is the start, not the finish. The install count that accumulates after launch directly affects your visibility in WordPress.org search results — plugins with more installs rank higher. Understanding how the WordPress.org search algorithm actually works and optimizing your readme for the right keywords is what separates plugins that compound over time from ones that stagnate at 50 installs.

Troubleshooting Common Errors
Authentication failed. Make sure you’re using your WordPress.org username and password — not your hosting credentials. If you have two-factor authentication on WordPress.org, you may need to use an application password.
svn: E155010 — not a working copy. Your SVN checkout path in the script (PLUGIN_SLUG combined with the expected checkout location) doesn’t match where you actually ran svn checkout. Open the script and verify the path resolves correctly.
Files not showing in WordPress.org after commit. Most commonly a version sync issue — verify all three match. Also confirm your SVN tag was created before you committed: if you committed trunk changes without tagging, existing users won’t see an update prompt.
rsync: command not found (Windows). rsync isn’t available in Git Bash by default. Use WSL instead — sudo apt install rsync inside WSL handles it cleanly.
svn: E170013 — Unable to connect to repository. Network issue or WordPress.org SVN server is temporarily unavailable. Wait a few minutes and try again — this is rarely a configuration problem.
Further Reading
- How to Rank Your Plugin on WordPress.org — once your plugin is deployed, this is how you make sure people actually find it.
- The 7 Fields WordPress.org Actually Indexes — the fields that drive keyword relevance in the plugin directory algorithm.
- How to Spy on Any Competitor’s WordPress.org Plugin Keyword Strategy — find the keyword gaps your competitors are winning before you optimize your readme.
- We Got Our Own Plugin Shut Down. Here’s How It Made Our New One Better. — what happens when a plugin gets closed by WordPress.org, and what we learned building the guardrails to prevent it.
- WordPress.org Developer Handbook: How to Use Subversion — the official reference if you want to go deeper on SVN specifics.
Who knew the hardest part of publishing your first WordPress plugin wasn’t the code — it was learning that 2005 called and it wants its version control system back.
