Git Submodules & Monorepo Alternatives
debt(d7/e7/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints note automated=no and the only tool is git itself. Problems like a missing --recursive flag, detached HEAD confusion, or stale submodule pointers typically surface as CI build failures or broken clones rather than being caught by any linter or static tool. The .gitmodules pattern can be spotted in review but isn't flagged automatically.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix says to 'prefer Composer packages over git submodules for PHP dependencies', which means replacing a submodule with a proper versioned package. This touches CI configuration, clone scripts, build pipelines, developer workflows, and potentially multiple repositories — it's a cross-cutting change across tooling and team practice, not a single-file fix.
Closest to 'strong gravitational pull' (b7). Submodules apply_to 'any' context and once adopted they shape every developer's clone workflow (--init, --recursive), CI pipeline setup, and shared-library update process. Every future change to the shared code requires updating the parent pointer and coordinating across repos. The structural debt reaches broadly across the team and toolchain.
Closest to 'serious trap' (t7). The misconception is explicitly documented: developers believe submodules are the best way to share code between repos, when in fact Composer packages with semantic versioning are far superior for this use case. The common mistakes reinforce this — detached HEAD confusion, forgetting --init, stale pointers — all contradict the expectation that submodules behave like ordinary directory dependencies. This is a well-known gotcha that contradicts reasonable developer intuition.
Also Known As
TL;DR
Explanation
Git submodules: a repository nested inside another, pinned to a specific commit. Common problems: easy to forget to commit submodule updates, new contributors miss git submodule update --init, detached HEAD confusion, and complex CI setup. Alternatives: git subtree (merges subtree history into main repo, no nested .git), monorepo (all code in one repo with build tool), Composer packages (proper versioning + dependency resolution). For PHP: Composer with a private Packagist is almost always better than submodules.
Common Misconception
Why It Matters
Common Mistakes
- Committing changes to submodule without updating the parent repo's pointer
- Forgetting git submodule update --init on fresh clone — builds fail
- Using submodules for external dependencies — use Composer/npm instead
- No --recursive flag in CI clone — submodules are empty
Code Examples
# Developer updates submodule, forgets to update parent:
git -C shared-lib commit -m 'Add feature'
# Forgets: cd .. && git add shared-lib && git commit
# Other developers: still get old version
# New clone:
git clone repo && ls shared-lib/ # Empty! Forgot --recursive
# Composer private package instead:
# composer.json:
# {"require": {"company/shared-lib": "^1.3"}}
# Developer A releases update:
# git tag v1.3.0 && git push --tags
# Consumer updates:
# composer update company/shared-lib
# Explicit version, CHANGELOG, proper dep resolution