Using Git Submodules to Manage Plugins in Rails

by Mike Zazaian at 2009-08-30 22:01:45 UTC in plugins versioning rails

a really useful way to utilize git submodules to maintain plugins in your Rails application without making constant changes to your git repository

1 comment 2 links

I've written a bunch of really massive, lengthy tutorials lately, and thought it a good time for something brisk and useful.

The submodules feature of Git is just that. It allows you to maintain plugins (and other bits of code) from within your git repository without having to do so much as run the plugin script in your Rails application.

Plugin updates, too, become much easier via git submodules, considering that you'll only have to type a single command to refresh plugin code from the original repositories of those plugins. No deleting, no copying -- it's super easy, and you should be using it.

Luckily, I'm about to show you how.

creating a submodule

So let's suppose that you've already got your git repository setup, and after reading the article that I wrote about syntax highlighting solutions your entire view of mankind has been altered and you want to make the world a better place by implementing arya's tm_syntax_highlighting plugin in your Rails app.

Now ordinarily if you were to just install the plugin via /script/plugin the process would look something like this:

$ cd my_app
$ ./script/plugin install http://github.com/arya/tm_syntax_highlighting/tree/master
$ git add .
$ git ci -m "Added tm_syntax_highlighting as a plugin, am one step closer to changing the world"

Which would certainly be prudent, and you'd be well on your way to solving hunger in Africa, and would perhaps even extend to improving some of the variety shows performed in modern-day, East Berlin. Truly, either of these would be massive feats in and of themselves.

But suppose also that our friend arya is feeling really antsy this week and ends up committing eighteen new features to the plugin's repository on github. All of the sudden you're spending about an hour and a half over the course of the week manually deleting the plugin from your rails app and re-installing it just to keep it current, which saps all of the time that you had set aside for teaching Canasta to blind children, so now they're going to have to learn Crazy Eights. Life's just tough like that sometimes.

Had you been wise, though, and installed tm_syntax_highlighting as a git submodule, you'd still have that hour and a half with which to teach those blind children Canasta, Crazy Eights, and any other games that might strike your fancy.

It's super easy, watch:

$ git submodule add http://github.com/arya/tm_syntax_highlighting/tree/master ./vendor/plugins/tm_syntax_highlighting

Initialized empty Git repository in /home/username/my_app/vendor/plugins/tm_syntax_highlighting/.git/
remote: Counting objects: 75, done.
remote: Compressing obremote: jects: 100% (44/44), done.
Receiving objects: 100% (75/75), 21.76 KiB, done.
remote: Total 75 (delta 20), reused 75 (delta 20)
Resolving deltas: 100% (20/20), done.

So as you see, we're creating the actual submodule with git submodule add http://github.com/arya/tm_syntax_highlighting/tree/master, and we're telling it go where we put the rest of our plugins with ./vendor/plugins/tm_syntax_highlighting.

Neat. If you call git status now you'll see that there's a new file in the root directory of our Rails app called .gitmodules, which looks something like this:

#!/.gitmodules

[submodule "./vendor/plugins/tm_syntax_highlighting"]
  path = ./vendor/plugins/tm_syntax_highlighting
  url = git://github.com/arya/tm_syntax_highlighting.git

As you see, it just sets url to the path of the plugin's repository, and sets path to the directory where the plugin will be installed and updated in our Rails app. Superneat, even.

Now all you have to do is perform a quick:

$ git add .
$ git commit -m "My submodule is amazing and now I'm TRULY ready to change the world"

And you're ready to rock and/or roll.

updating submodules

One of the places where submodules really shine is in the ability to easily update them from an external repository.

No, Git won't automatically pull the current submodule code from its external repository, but because submodules model external repositories git treats them as such and makes them just as easy to update manually. Observe:

$ cd /vendor/plugins/tm_syntax_highlighting
$ git pull
Already up-to-date.

Obviously, if some time had passed, and there had been changes to the repository, it would give us a different message than "Already up-to-date." Noe that you'll have to do this for each of the submodules that you've created whenever you'd like to pull the most recent code from the repository.

The process seems like it might be easier if Git just automatically updated a submodule each time its repository was updated, but then you, the user, wouldn't be afforded the flexibility of selecting which updates to pull into your Rails app. Eh -- it's six of one, half a dozen of the other.

submodules in capistrano

Suppose also that you're deploying your Rails app to a server regularly with Capistrano. You're in quite a bit of luck here, as Capistrano can be configured to automatically deploy submodules from their respective repositories, directly to the Rails app deployed on your server.

It's pretty easy. Just add the following line to your /config/deploy.rb file:

#!/config/deploy.rb

set :git_enable_submodules, 1

Then you can just deploy your Rails app with capistrano as you would in any other circumstances, with cap deploy. This time, however, you'll see some output for all of the repositories that you've added as submodules. A thing of beauty.

one last thing

Suppose for whatever reason that you'd like to expand this notion of saving the world to one of saving the galaxy. No, you're not necessarily a pragmatist, but you're a dreamer and the world needs dreamers.

You might then want to create a remote repository for your Rails app on github so other dreamers can clone your app from the remote repository and spread the dream.

So -- if and when this day does indeed come, you'll have to remember one thing. When other dreamers clone your Rails app, or any other application that uses git submodules from a remote repository, they'll have to initialize the code for those submodules before using the cloned repository:

$ git clone git://github.com/world-savr/world_saving_rails_app.git
$ git submodule init    # this is the important part
$ git submodule update  # so is this

That's it. Now your lackie/associates can propagate your world_saving_rails_app with a whole spectrum of submodular goodness.

fin

Yeah, I guess this wasn't as short and sweet as I had initially intended it to be. Sweet, yes. Short -- yes, but only relative to War and Peace. In the words of Kurt Vonnegut, "so it goes." Rails is fun and Git is fun and Submodules are fun and when you get all of them together it makes a barrel full of monkeys look like the flood insurance booth at a real estate expo.

Whatever the case, you now know how to implement git submodules, and regardless of whether your ultimate ambitions are those of saving the world or destroying it, your Rails apps will be cleaner, lighter, and easier to maintain and deploy.

As a great man once said, submodularity is next to godliness. Thank you, git submodules, you kept us out of war.

1 comment

Voldy at 2009-12-31 08:26:36 UTC

Very cool article! Thank you very much, specially for Capistrano receipt!

Comments closed

latest links

Help.GitHub - Multiple SSH keys The article from github help mirroring this process
ones zeros majors and minors ones zeros majors and minors: esoteric adventures in solipsism, by chris wanstrath
ActiveScaffold A Ruby on Rails plugin for dynamic, AJAX CRUD interfaces

login

register activate reset

feeds

articles/rss

topics

staff

editor

about

doblock focuses on ruby, rails, and all things that can help ruby and/or rails programmers hone their skills.

Techniques, tutorials, news, and even free open-source applications, doblock seeks to fill in the cracks of the ruby/rails blogosphere.

doblock v. 0.10.1 powered by Rails