Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

  • Blog Navigation
Best practices for managing external plugins/libraries which live in Git?

This question came up at standup. I’ve put some thought into it, so I thought I’d throw it out for discussion and see what other people think.

At Pivotal, we use svn:externals and the Third-Party Branch Pattern (from the SCM Patterns Book) to manage easy, reliable cross-project updates of common plugins which live elsewhere (rubyforge, etc), without having to manually update in every project or be at the mercy of the RubyForge svn repo going down or being slow. When everything was on SVN, this worked well; we had some rake tasks which made it easy to update the branch from the latest trunk version in the external vendor repository. However, with more stuff like Desert is moving to GitHub.

One option is to just check the entire Git repo into subversion. This is labor-intensive, though. It also loses some of the benefits of the Third-Party branch pattern, such being able to easily preserve local patches while still pulling in changes from a new vendor version. We could probably update our Rake tasks to handle Git as well as SVN.

Another option is to switch all our projects to Git, but we aren’t quite ready for that across the board.

Plus, this is a problem even if you move your parent project to Git. For example, there is no easy Git equivalent to having a svn:external which automatically updates to the latest version of an external repository, which is a useful approach for Continuous Integration or automatically pulling the latest Edge Rails into your project on every update.

Here’s some links from people working on related issues, but please comment if you have any ideas or something that works well for you:

  • The latest Piston (, but for the latest check for info about “Piston 2”) from source handles a mixture of git and svn plugins.

    You can use it if your own repository is either git or svn based, too.

    For how to grab it from source, check


  • I’m pretty sure git submodules are exactly a substitute for svn:externals.

  • Kyle,

    git submodules are at best a seriously flawed replacement for svn:externals. The submodules approach has numerous problems, particularly when you try to switch between branches that do not have the same submodules. You will regularly get conflicts and failed merges because each submodule is a complete git repository separate from the parent repositories.

    These problems have been noted in numerous posts around the Rails community. We have actually completely stopped using submodules due to the issues.

    Once Piston is finally working properly with git, we will probably use it again. I enjoyed using it with SVN.

    Best of luck,


  • Chad Woolley

    Great comments, thanks a lot. I had not heard of Braid, it looks promising.

    However, I still don’t see anything equivalent to the complete automation of svn:externals. In other words, when I do a git pull, I want my subtree (or whatever) to automatically get updated too. I’m still learning git, is there some way I can do a post-pull hook to automatically invoke Braid or something? That’s what I’d really like…

    Thanks again for the responses,
    — Chad

  • Brian Takita

    One thing I didn’t like about Braid is that you get the entire history of the tracked project. This causes the size of you repo to be massive if you use Braid to track projects with a long history, like Rails.

    Perhaps there is an option to limit the size of the repo you are tracking. I’m not aware of a solution.

    Using git externals works well enough for projects that are not a dependency to other projects. Unfortunately, git externals do not seem like a good fit for libraries because git does not seem to have a recursive submodule init and update functionality. Somebody please correct me if I’m wrong.

    Piston works well enough to sync the external in your project to the latest version. Unfortunately, changes are best made from the dependency with a piston update happening on the client library. This adds overhead to the development cycle.

Share This