Git Submodules
Now that everyone’s on Git, people are starting to play with submodules.
Here’s why you should too.
Just like svn:externals
- They aren’t stored in your repository.
- Only a reference to the location is stored (can be local or remote)
Just like Piston
- A reference to the commit is stored. It will be tied to that revision until you say otherwise.
This sounds kinda confusing, and at least one aspect is probably not what you expect.
Example
For MicroRevie.ws, I wanted to add Rails as a submodule, as I like living on the edge. I used Koz’s version on GitHub (since the official Rails git repo isn’t yet available), so in my git project I typed:
git submodule add git://github.com/NZKoz/koz-rails.git vendor/rails
This tells git where the code is from (remember, this could be local too) and where I want it to live.
If I then run git status I’ll see a new file called .gitmodules. The file looks like:
[submodule "vendor/rails"]
path = vendor/rails
url = git://github.com/NZKoz/koz-rails.git
Fantastic! Once I git add and git commit the files, they’re locked into my repository. They are not stored in my repository, however, just references. When I push the main MicroRevie.ws project up to GitHub, it small and fast (better than Piston!).
When Matt pulls down his copy of the project, he needs to run these two commands to use the submodules:
git submodule init
git submodule update
Updating a submodule
Here’s where submodules are more like Piston. You must explicitly update submodules. Here are the steps:
cd vendor/rails
git pull
cd -
git commit -a
Or in English: go into the submodule, pull updates, then get out and commit.
When you commit, you are again only committing a change in reference. You’re not storing tons of new updates, just a reference to the new revision. You can even go backwards, but that’s left as an exercise for the reader.
When Matt wants to get my changes, he can’t just do a git pull. He has to also type:
git submodule update
And he’ll be updated to the version I committed.
Is it worth it?
Yes. However, I’ve defended (and simultaneously cursed) svn:externals, so I’m not the final judge.
In the end though, I really like git submodules better than either externals or Piston. For me it comes down to:
- Don’t need any extra software (such as Piston, and yes I’m aware of Braid)
- Doesn’t clog up my repository with tons of extra files (Piston, again.)
- Doesn’t force me to the newest version (
like externals doUpdate: Mark points out in the comments that svn does allow you to specify a revision. Very good catch!, such as when Rails or rspec make incompatible changes… which has happened)
Try them out. At worst, you’ll remove the references and be out a few minutes of your time.
Comments
-
Thanks for the info on submodules Dan. Just a slight correction in regards to SVN externals though. Externals do allow you to specify which revision you want to be tied to, for example:
rails -r9243 http://svn.rubyonrails.org/rails/trunk
-
Mark,
Good point. Maybe I’m too hard on svn, by only pointing to the common (non-version-specified) use case.
-
Daniel, Good post, but isn’t there a small advantage to a piston or braid-like approach where all the files are in your own repository? What happens during deployments? Doesn’t the deployment now rely on a possible many remote repositories to succeed? Consider both
vendor/railsand a possible manyvendor/pluginseach with their own submodule.I think I also missed an important point. How does Matt’s
git submodule updateavoid pulling a later version of edge rails than the original revision that you intended? The .gitmodules file only seems to specify the public clone url without any commit revision. -
Good comments, Ryan. I posted a follow-up.