We were having trouble figuring out the best way to handle our application's external git dependencies at Bleacher Report. We wanted to be able to "freeze" externals to simplify project setup and deployment. We also wanted our developers to be able to quickly unfreeze externals, work on them, and freeze them back.

Submodules and cached_externals did not fit those requirements. I really like giternal, which works well (and has a way cool name), but I don't like how it shares a single gzipped .git snapshot across all users on a repository. I also think it could be made simpler in some areas. Many thanks to Pat Maddox for getting the ball rolling.

Introducing externals. Let's install the gem.

Terminal:

gem sources -a http://gems.github.com
sudo gem install winton-externals

Create a configuration file.

my_repo/config/externals.yml or
my_repo/.externals.yml:

rails:
  repo: git://github.com/rails/rails.git
  path: vendor

Freeze Rails into your repository.

cd my_repo
externals freeze

You should see a frozen copy of Rails in your vendor directory. Now you can commit to your parent repository like normal.

git add .
git commit -m "Freezing Rails"
git push origin master

When you unfreeze an external, it becomes its own repository again. Let's pull the latest changes from the Rails repository.

externals unfreeze
cd vendor/rails
git pull origin master
cd ../../
externals freeze

You can also freeze and unfreeze specific externals using a regular expression match.

This would also freeze rails:

externals freeze ra

In case you can't remember the freeze state of your externals:

externals status

And last but not least, some nifty shortcuts:

externals st # status
externals fr # freeze
externals un # unfreeze

An additional thanks to Tung Nguyen for helping me get this to 1.0.0 and ovoice for updating the wiki.

More details on the externals GitHub page.