How to checkout old git commit including all submodules recursively?

You need two commands to achieve this:

git checkout *oldcommit*
git submodule update --recursive

Update: This answer is outdated as of 2018 – see VonC's answer below for more current information.


Note: if you have multiple submodules (and submodules inside submodules), Git 2.14 (Q3 2017) will help (more recent that the OP from 2013)

git checkout --recurse-submodules

Using --recurse-submodules will update the content of all initialized submodules according to the commit recorded in the superproject.
If local modifications in a submodule would be overwritten the checkout will fail unless -f is used.

"git checkout --recurse-submodules" did not quite work with a submodule that itself has submodules. It will with Git 2.14.


Note: with Git 2.19 (Q3 2018), git checkout --recurse-submodules another-branch is more robust.
Before, it did not report in which submodule it failed to update the working tree, which resulted in an unhelpful error message.

See commit ba95d4e (20 Jun 2018) by Stefan Beller (stefanbeller).
(Merged by Junio C Hamano -- gitster -- in commit 392b3dd, 24 Jul 2018)

submodule.c: report the submodule that an error occurs in

When an error occurs in updating the working tree of a submodule in submodule_move_head, tell the user which submodule the error occurred in.

The call to read-tree contains a super-prefix, such that the read-tree will correctly report any path related issues, but some error messages do not contain a path, for example:

~/gerrit$ git checkout --recurse-submodules origin/master
~/gerrit$ fatal: failed to unpack tree object 07672f31880ba80300b38492df9d0acfcd6ee00a

Give the hint which submodule has a problem.