I am in a situation where I cannot use submodules (or subtrees, I believe), and I can only use vanilla nested repos (the reason is somewhat unusual, but it has to do with building inside a docker container).
In general, what are the issues with nesting vanilla git repos in this manner?
2019: A nested Git repo has no problem, except its parent repo will see it as a gitlink (a special entry in its index, representing a SHA1)
The problem is: that SHA1 reference has no URL reference, so cloning again the parent repo will lead to an empty folder, because the parent repo does not know where to search for the nested Git repo.
This differ from a submodule, which records the gitlink (same as a nested repo) and the URL of the nested repo (in a special file: .gitmodules)
If your parent repo ignore (in a .gitignore) the nested repo entry, then both can co-exist without issue.
2025 update: TL;DR
The description above is still essentially correct. The extra gotchas people hit are:
Longer version:
A nested repo only becomes a special gitlink entry (mode 160000, just a commit SHA)
once you git add the directory:
# outer repo
git add inner/
git ls-files -s inner/
# 160000 <sha1-of-inner-commit> 0 inner
If you instead ignore it:
echo "inner/" >> .gitignore
git add .gitignore
git commit -m "Ignore nested repo inner/"
then the parent never records anything about inner/ – it is just an untracked
directory as far as the outer repo is concerned.
If you commit inner/ as a gitlink but do not use submodules:
A fresh clone of the parent gets an empty inner/ directory (no URL is
recorded, so Git does not know where to fetch from).
Some commands treat it as a missing submodule mapping, like:
git submodule status
# fatal: no submodule mapping found in .gitmodules for path 'inner'
So it "works", but UIs and teammates may see it as a half-configured submodule.
If the parent ignores inner/ completely:
Checking out an old commit of the parent does not tell you which commit of the nested repo to use – any pairing has to live in docs/scripts:
# outer/inner-version.txt
inner commit: <sha1>
Tools run in the outer repo (git grep, git archive, some CI jobs) simply
do not see the nested repo's contents at all – it is invisible to the parent.