Using Git Submodules to Manage Plugins in 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 linksI'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.
Very cool article! Thank you very much, specially for Capistrano receipt!