Git to SVN: Automated WordPress Plugin Deployment

During my daily commutes through Version Control land, I’d gladly never leave Git’s bountiful pastures. Alas, to deploy my WordPress plugins, I must check-in my code to a Subversion repository on plugins.svn.wordpress.org.

There are a few tutorials floating around the web which help we laymen understand how to make Git & Subversion play nice together. With my number of plugins increasing and having previously worked for an automated build tool developer, I knew I should aspire to one-step deployment.

A quick Google on the matter lead me to Dean Clatworthy’s WordPress Git-SVN Deployment script, which was a great start. Only one problem – it required I keep a copy of the SVN repo locally. I didn’t want to do that - I change computers more often than I change socks.

I also wanted the deployment script to live in each of my plugin’s Git repos (without deploying the script file and GitHub README.md to WordPress.org). So I made a few modifications and thus was born my one-step Git to SVN WordPress Plugin Deployment Script.

To use it, add deploy.sh to the root of your Plugin’s Git repository. Specify a few plugin specific variables at the beginning of the file, then it’s ready to run. Make sure it’s executable (chmod u+x deploy.sh) and from the command line, you can deploy anytime with:

./deploy.sh

If you’re not already using an automated deployment for your WordPress plugins I highly recommend it. Since running the script for my plugins, I’ve not suffered the frustrations of minor errors – like having version numbers in the readme.txt & plugin file differ. I’ve lost less time deploying, so I’ve released more frequently, which means fewer bugs in the wild. Win.

About Brent

Born to code.
This entry was posted in Blogdex, WordPress and tagged , , , , , . Bookmark the permalink.

56 Responses to Git to SVN: Automated WordPress Plugin Deployment

  1. Boone Gorges says:

    Very cool. Thanks for sharing.

    I’m going to play around to see if there’s a way to integrate wp.org’s .pot generation tools into this process. I always forget to refresh the language file before release, so it’d be great to have it regenerated and committed to the repo automatically before release.

    • Brent says:

      That would be very cool also. I’ve also considered some of the other things I could do (auto updating version number etc.).

      If you add to it, please let me know, I’d love to add the changes.

  2. Ray says:

    I like the idea of your automated approach, Brent.
    However, I’m not sure what you mean by not having a local SVN repo.

    Would that mean I would have to download the latest version of my plugin into my local Git repo before using your approach?

    For example, I have a plugin on the WP extend repo called “my-plugin”. I create a new, local directory called “my-plugin”. Next, I download the plugin from the WP extend repo and put the files in “my-plugin”. Is this right?

    And then, it’s the usual? Develop in Git, test changes, update version numbers in readme.txt and in the plugin’s main PHP file.

    Lastly, run deploy.sh with all my variables filled in?

    Does all this sound correct?

    • Brent says:

      Hi Ray, other than setting the SVN repo variables in deploy.sh, you don’t need to worry about the SVN repo at all. Develop in Git, then when you are ready to deploy, just run deploy.sh and the rest is taken care of. :)

      Deploy.sh checks out your plugin from WordPress Extend’s SVN repository. It stores it in a temporary folder defined by the SVNPATH variable, which by default is:

      /tmp/my-plugin/

      In line 14 of deploy.sh the SVNPATH is being set. Then deploy.sh checks out the repo into this temporary path in line 51.

      • Ray says:

        Thanks for the reply, Brent.

        One thing I forgot to mention in my first post is I’m starting with an empty Git repo.

        So what I’m guessing to do is just download the latest version of my plugin from WP extend and push that to my Git repo. Then, follow your steps above; do some developing and commiting and lastly use your deploy.sh script to push to both SVN and Git.

        Does all this sound about right?

        A few other things:

        1) I noticed that the deploy.sh script checks if the readme.txt’s version number and the PHP plugin’s version number are identical. This means that the script doesn’t allow you to push a dev version of your plugin to WP extend.

        I guess this isn’t really a big deal, since you can always tell your users to download a tagged beta from Git.

        2) Using your approach, will my entire plugin’s SVN commit history be reflected in Git as well? (Sorry if this is a daft question, but I wasn’t sure.)

        • Brent says:

          Hi Ray, deploy.sh is written so that I can working entirely in Git with Github, then deploy (in one step) to wordpress.org when I want to tag a new major release. It could be changed to account for pushing smaller batches of work to SVN, but for my needs, I was happy to keep the history in Git and only commit new versions to SVN.

          Also, I start in Git so the script doesn’t account for merging an SVN repo. To merge your existing repo, I’d do a Google as there are tutorials on how to import an SVN repository into Git without losing your history.

          • Ray says:

            Thanks for the quick reply, Brent!
            I’ll grab my SVN history into Git first before using your script.

    • Randi says:

      Short, sweet, to the point, FREE-exactly as inrfomatoin should be!

  3. Pingback: Deploying from Git to WordPress SVN | Daniel Langer

  4. Looks like a great solution for anyone wanting to migrate van SVN to Git. So, if I understand correctly, I work on my code locally in my Git repo, when done I commit it to my online Git repo and additionally locally run the deploy.sh script, right?

    I assume it will prompt me for my SVN password btw?

    • Brent says:

      Yep exactly. Work entirely in Git then run ./deploy.sh when you also want to commit/deploy to the wordpress.org SVN repo. If you are not authenticated with the wordpress.org SVN you will be prompted for your password, otherwise the process will be entirely automatic.

  5. Is it possible that I create a new site of master files, (initial WordPress install – customize to taste), turn that into a local repo and then use Git to publish? I have some new projects I’d like to set up. Is there anything from stopping me from using Git after I’ve locked my design and initial files?

    I’m trying to bypass SVN altogether since these are new projects. Thanks for any advice!
    (P.S. I’m relatively new to Git but learning quickly and have never used SVN)

    • Brent says:

      Hi David, nothing stopping you from doing that. This article is mainly about deploying to WordPress.org Plugin’s repository, which is SVN.

      There are a few articles about how other folks have achieved similar to what you’re after, a quick google should take you to them. :)

      Good luck!

  6. OMG, THANK YOU THANK YOU THANK YOU.

    You’re a life saver.

  7. Hi Brent, thanks for the great script!

    I have a question though: if your plugin development is in Git, how do you go about ensuring that your bundled POT file is updated to match the new changes?

    If working in SVN only, I typically commit my updates to trunk (with the stable tag set to a tag not trunk), then use the “Generate POT file” function that is on http://wordpress.org/extend/plugins/your-plugin-name/admin/, download that POT file, commit it back to SVN trunk, and then tag the new version from the latest SVN trunk.

    Do you know of a way to generate an updated POT file based on your git repository file’s contents?

    Thanks!

    James

    • Brent says:

      Hey James, the Codex article on generating a POT file mentions that you can download and install the WP.org POT generator and run it through php via terminal:

      Checkout the wordpress-i18n tools directory from SVN (see Using Subversion to learn about SVN) and then run the makepot.php script like this:

      php makepot.php wp-plugin your-plugin-directory

      You need the gettext (GNU Internationalization utilities) package to be installed in your server before you can run the above command (and you must use svn to check out the wordpress-i18n tools, rather than downloading them from the URL above). After it’s finished you should see the POT file in the current directory.

      I haven’t tried it, but it’s worth a shot.

      • Well spotted Brent. Installing gettext on OS X looked difficult, but I got it all up and running on my Debian VM in only a few minutes.

        These commands generated an updated POT file based on the files in my /path/to/myplugin/ folder:

        `$ cd /path/to/myplugin/
        $ php /path/to/i18n-tools/makepot.php wp-plugin . languages/myplugin.pot`

        (in that example I keep my POT file in /path/to/myplugin/languages/mypluign.pot)

        In your script, you’d probably use those commands to generate an updated POT file, commit the new POT file to your github repo, and then from there do your normal deployment steps which would deploy the plugin’s code (including updated POT file) to the WP.org SVN repo.

  8. Pingback: Git et Subversion : quand plus rien ne va | Eolya Consulting

  9. Neil Pie says:

    This is a really useful script Brent, thanks. Am I correct in thinking that it will create only one SVN revision, rather than a history of all your git commits?

  10. Thanks, Brent—I could not for the life of me get my plugin to update in the WP repository. As soon as I tried this script, it worked right away! This will prevent me from having to maintain a git and svn copy on my machine—thanks a lot!

  11. Pingback: Moved my WordPress plugins to GitHub | Coen Jacobs

  12. bftrick says:

    Thanks Brent! You took a complex process and made it simple. You rock. :)

  13. Dave says:

    Great script. I have a rather complex plugin that is a work in progress, and I’ve removed a few subfolders throughout these iterations. However, while these subfolders no longer exist in my local repo / github repo, they still show up in my trunk. It seems as though WordPress SVN is hanging on to them from past versions for some reason. Is this something that can be corrected in the script?

    • Brent says:

      Depending on your file structure, you’ll need to delete the folders from the repo and then commit the changes, or delete them from the SVN repo using svn rm.

      If you are regularly changing folder/file structure, you can also add a lines to the script to remove all files in the SVN directory before doing the git checkout so that a clean version of your git repo is always checked out.

      • Dave says:

        Could you give me an idea of what to add to the script in order to remove all files in the SVN directory?

  14. Pingback: Van WordPress SVN naar Git | Remco Tolsma

  15. Pingback: Milestone for WordPress self-hosted v0.9 – Andrew Ferguson dot NET

  16. Hi Brent, I commented a few months ago about this script and it’s worked great. I did run into an issue uploading screenshots and the banner image to the svn repo. They are located in the /trunk/assets folder instead of the /assets/ folder. Any suggestions?

    • Brent says:

      To do it automatically you could just add normal bash commands to move the images into /svn-repo-name/assets/ after the script runs checkout-index and just before the files are all committed.

      Adding something like this to line 75 do it (but is untested):

      echo "Moving assets"
      rm -fr $SVNPATH/assets
      mv -f $SVNPATH/trunk/assets $SVNPATH/
      
      • bftrick says:

        I tried [updating the deployment script](https://gist.github.com/3767319) but it didn’t work quite right. Do I need to add some sort of commit after that?

        • Brent says:

          Read my comment again:

          after the script runs checkout-index and just before the files are all committed

          You’ve added it after the files are committed. :)

          • bftrick says:

            I’ve updated the script (see previous link) and it creates the assets folder with the right files but it doesn’t commit it.

            I’ve temporarily commented out the second-to-last line to look at the svn repo and the assets folder is indeed there. If I run an `svn status` command I get a `? assets` which means that it isn’t under version control. If I run `svn add assets` I get `svn: warning: ‘assets’ is already under version control` and I still can’t commit it.

            Thoughts?

          • Brent says:

            Argh, forgot we were working with SVN not Git. SVN won’t like the entire assets dir being deleted. We need to replace just the items in the assets folder. Try this:

            echo "Moving assets"
            rm $SVNPATH/assets/*.png  $SVNPATH/assets/*.jpg
            mv $SVNPATH/trunk/assets/* $SVNPATH/assets/
            rm -fr $SVNPATH/trunk/assets 
            
          • bftrick says:

            Holy cow, I made a couple tweaks and it finally works! I’ll write up a blog post soon. Thanks so much!

          • Brent says:

            Great to hear! Be sure to send me a link when you get it up. :)

            I’ve done a few tweaks in private Git repo’s to generate translation files automatically too, so I might do an updated post with these tweaks and those sometime to unleash the “Super Mega WordPress Plugin Deployment Script” haha.

          • Hey Brent. I finally updated the script with the changes we talked about. You can see the script on my blog.

            Thanks for all your help. :)

        • @bftrick – did you sort out how to get the /assets uploaded correctly?

  17. I wonder if there is a way to remove SVN entirely from the process. Can’t git talk to SVN repos using git-svn?

  18. Pingback: Att använda Git för Wordpress plugins | Mediascreen

  19. phikai says:

    I notice that you mention git-svn doesn’t work with submodules, but it appears the deploy script doesn’t work with them either… any thoughts/modifications to make things work with submodules?

    • Brent says:

      Hrm surprised I missed that! Here are two potential solutions (there are others, but these are two).

      1. Instead of using git checkout-index recursively copy the entire contents of the git directory to the SVN directory using cp. So something like:
        # git checkout-index -a -f --prefix=$SVNPATH/trunk/
        cp -fr ../ "$SVNPATH/trunk/"
        
      2. Use git archive-all to create an archive everything, then unarchive it into the temporary directory, something like:
        git archive-all --prefix=$SVNPATH/  | tar x -C"$SVNPATH/trunk/"
        

      I haven’t tested either solution, but they should put you on the right path to including in the script.

  20. What do I do when I receive a message like this:

    readme.txt version: 2.1.1
    bptpi.php version:
    Version in readme.txt & bptpi.php don’t match. Exiting….

    • Brent says:

      Set the correct version number in both readme.txt & bptpi.php. It checks the versions to make sure they match. If they are different, it assumes one wasn’t updated correctly.

  21. Belicio Torres says:

    Awesome work, and totally saving my bacon. Wonder if I missing something? Does this script delete the files in the SVN remote directory that are no longer in my GIT space?

    Currently, I see this happening: file_foo.php is no longer needed. I delete it and update GIT. I run the script, to update WP SVN, and file_foo.php lingers…

    Is this expected behavior? Could it not be?

    (I see you script in your project, and a few derivatives out there… but would be great to get a definitive GIT going so we can add pull requests.)

    Please pardon my english.

  22. Pingback: WordPress.org vs. GitHub For Hosting WordPress Plugins and Themes

  23. Thought you might like to look at https://github.com/aubreypwd/deploy-git-wordpress-org It’s my version of a deploying plugins to WordPress.org script. It accepts the plugin file, username for WordPress.org, and only makes updates to readme.txt if you want it to.

  24. Pingback: Moved my WordPress plugins to GitHub - Coen Jacobs

Comments are closed.