From e7e8cc8bf9b45ad8fa0b84c24e032037f2214265 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 22 Jul 2026 06:21:04 +0000 Subject: [PATCH 1/2] docs: add Git submodules concept article Rewrite submodule mechanics into a house-voice learn doc covering gitlinks, .gitmodules, gitdir storage, and common sync commands. Co-authored-by: Ziinc --- web/learn/concepts/git/git-submodules.mdx | 110 ++++++++++++++++++++++ web/learn/concepts/git/index.mdx | 5 + web/sidebarsLearn.ts | 1 + 3 files changed, 116 insertions(+) create mode 100644 web/learn/concepts/git/git-submodules.mdx diff --git a/web/learn/concepts/git/git-submodules.mdx b/web/learn/concepts/git/git-submodules.mdx new file mode 100644 index 00000000..66134c5d --- /dev/null +++ b/web/learn/concepts/git/git-submodules.mdx @@ -0,0 +1,110 @@ +--- +sidebar_position: 6 +--- + +import DefinitionCard from "@site/src/components/DefinitionCard"; + +# What are Git Submodules? + +_Git submodules embed another repository inside a parent repository and pin it to an exact commit._ + +## Introduction + +A **Git submodule** lets a primary repository, called the **superproject**, record an independent Git repository as a subdirectory. The superproject does not copy the submodule's blobs or trees into its own object store. It stores a pointer to one commit in the submodule's history. + + + + + +That design keeps each dependency's history separate. Clones can still rebuild the same composite project from recorded pins. + +## Understanding the Concept + +Git records a submodule as a **gitlink**: a tree entry with file mode `160000`. That mode means the entry is a commit pointer. It is not a normal file blob, and it is not a nested subdirectory tree. The hash in the tree is the submodule commit the superproject expects. + + + +When you check out a superproject commit, Git places the submodule at that recorded commit. The submodule working tree is usually in a detached `HEAD` state. The superproject pins history by hash. It does not follow a moving branch tip unless you ask it to. + +Submodule metadata lives in `.gitmodules` at the root of the superproject. That versioned file maps each submodule's name to its path and remote URL. Clones use those entries to recreate the same nesting. + +```ini +[submodule "vendor/lib"] + path = vendor/lib + url = https://github.com/example/lib.git +``` + +Modern Git keeps the submodule's real repository data under the superproject at `.git/modules//`. Inside the submodule working tree, `.git` is a file with a `gitdir:` line that points at that central store. You can switch branches or remove the working tree without deleting the downloaded submodule objects. + +{/* TODO: Diagram: superproject gitlink (160000) to submodule commit, and working-tree .git file to .git/modules//. */} + +## Applying It in Practice + +After cloning a superproject, map `.gitmodules` into local config and check out the recorded commits: + +```bash +git submodule init +git submodule update +``` + +`git submodule init` copies submodule URLs from `.gitmodules` into `.git/config`. `git submodule update` fetches the needed objects and checks out each registered gitlink commit. Many teams combine those steps with `git submodule update --init`. You can also clone with `--recurse-submodules`. + +To move a submodule to a newer upstream commit on its configured remote-tracking branch: + +```bash +git submodule update --remote +``` + +That fetch updates the submodule checkout past the commit recorded in the superproject index. Stage the new gitlink in the superproject if you want the parent history to track that newer pin. + +Before you push the superproject, confirm remotes already have the submodule commits you reference: + +```bash +git push --recurse-submodules=check +``` + +The check fails if the push would publish a parent commit that points at a submodule commit nobody else can fetch. That stops broken clones for collaborators. + +If someone changes a submodule URL in `.gitmodules`, local config can still point at the old origin. Sync the URLs, then update again: + +```bash +git submodule sync +git submodule update --init +``` + +`git submodule sync` rewrites the remote URLs in `.git/config` from the current `.gitmodules` values. Later fetches then use the new origin. + +## Engineering Considerations + +Treat the gitlink as the contract between repositories. The superproject history is only reproducible when clones can fetch the referenced submodule commit. + +Detached `HEAD` is intentional for that pin. If you need to change the submodule, check out a branch inside it before you commit. Commits made on a detached `HEAD` are easy to lose on the next `git submodule update` unless a branch or remote ref still points at them. + +Submodules and [worktrees](./git-worktrees) solve different isolation problems. A worktree adds another checkout of the same repository. A submodule nests a different repository and versions it by commit. Use clones when you need fully separate remotes and config without nesting. Use submodules when one project must pin another project's history in-tree. + +Keep `.gitmodules` and the staged gitlink hashes in sync during review. A parent commit that updates only one of those two records is hard to reason about later. + +## Scaling and Operations + +Large monorepos that vendor many submodules pay for an extra fetch and checkout step on every fresh clone. Automate `git submodule update --init` in onboarding and CI so missing checkouts fail early. + +Coordinate submodule pushes with superproject pushes. Prefer `git push --recurse-submodules=check` or `on-demand` in shared workflows. That keeps parent history from referencing submodule commits that remotes do not have. + +When a submodule remote moves, share the `.gitmodules` change and require `git submodule sync` before people update. URL drift often shows up as "commit not found" errors that look like network problems. + +Agents and scripts should treat the submodule directory as its own repository. Run Git commands with an explicit working directory or `-C` path. Expect detached `HEAD` after a normal update. + +## Next Steps + +- [What are Git Worktrees?](./git-worktrees): add parallel checkouts of one repository +- [Git Worktrees vs Clones](./git-worktrees-vs-clones): choose the isolation boundary you need +- [What is Version Control?](./version-control): revisit commits, trees, and repository history diff --git a/web/learn/concepts/git/index.mdx b/web/learn/concepts/git/index.mdx index acabf8f3..0a4ba47a 100644 --- a/web/learn/concepts/git/index.mdx +++ b/web/learn/concepts/git/index.mdx @@ -30,6 +30,11 @@ Start with Git's data model, then learn how to manage parallel and dependent bra href: "/learn/concepts/git/git-worktrees-vs-clones", label: "Git Worktrees vs Clones", }, + { + type: "link", + href: "/learn/concepts/git/git-submodules", + label: "What are Git Submodules?", + }, { type: "link", href: "/learn/concepts/git/merge-vs-rebase", diff --git a/web/sidebarsLearn.ts b/web/sidebarsLearn.ts index bb41b27a..ed5332ab 100644 --- a/web/sidebarsLearn.ts +++ b/web/sidebarsLearn.ts @@ -35,6 +35,7 @@ const sidebars: SidebarsConfig = { 'concepts/git/git-worktrees', 'concepts/git/git-worktrees-for-ai', 'concepts/git/git-worktrees-vs-clones', + 'concepts/git/git-submodules', 'concepts/git/merge-vs-rebase', 'concepts/git/cherry-pick-vs-rebase', 'concepts/git/stacked-prs', From a0ab15b98203b518ae3fd55a59f4a4ff159fb151 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 27 Jul 2026 11:32:49 +0000 Subject: [PATCH 2/2] docs: audit submodule writing and interlinking Add outbound body links from the submodules article, inbound prose links from worktrees and worktrees-vs-clones, and a version-control Next Steps entry so the page is no longer thin or orphaned. Co-authored-by: Ziinc --- web/learn/concepts/git/git-submodules.mdx | 12 ++++++------ web/learn/concepts/git/git-worktrees-vs-clones.mdx | 2 +- web/learn/concepts/git/git-worktrees.mdx | 2 +- web/learn/concepts/git/version-control.mdx | 1 + 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/web/learn/concepts/git/git-submodules.mdx b/web/learn/concepts/git/git-submodules.mdx index 66134c5d..951d3e72 100644 --- a/web/learn/concepts/git/git-submodules.mdx +++ b/web/learn/concepts/git/git-submodules.mdx @@ -10,7 +10,7 @@ _Git submodules embed another repository inside a parent repository and pin it t ## Introduction -A **Git submodule** lets a primary repository, called the **superproject**, record an independent Git repository as a subdirectory. The superproject does not copy the submodule's blobs or trees into its own object store. It stores a pointer to one commit in the submodule's history. +A **Git submodule** lets a primary repository, called the **superproject**, record an independent Git [repository](./version-control) as a subdirectory. The superproject does not copy the submodule's blobs or trees into its own object store. It stores a pointer to one commit in the submodule's history.