How do I commit changes in a git submodule?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
Committing a submodule change requires two separate Git commits because a submodule is its own repository. One commit records the actual file changes inside the submodule, and a second commit in the parent repository records that the submodule pointer now references a new commit.
Once that model is clear, the workflow becomes predictable. Most confusion comes from trying to commit only in the parent repository or from editing a submodule while it is checked out on a detached HEAD.
Why a Submodule Needs Two Commits
The parent repository does not store the submodule contents as normal tracked files. Instead, it stores a Gitlink entry that points at one specific commit in the child repository.
That means a submodule change is complete only when both of these are true:
- The new commit exists in the submodule repository.
- The parent repository records the updated submodule commit reference.
If you skip the first step, collaborators can fetch the parent repository but still fail because the referenced submodule commit does not exist on the remote. If you skip the second step, your submodule work exists, but the parent repository still points to the old revision.
Correct Workflow
Start from the parent repository and move into the submodule directory:
If the submodule is on a detached HEAD, switch to a real branch before committing:
Now commit and push the submodule changes:
After that, return to the parent repository and commit the pointer update:
The git add libs/parser command does not add all child files into the parent repository. It stages the new submodule commit reference.
Verifying the Result
A quick way to confirm the parent repository now points at the new submodule revision is:
You can also inspect the parent diff:
That output shows the old and new submodule commit IDs, which makes it easy to review what changed before the parent commit is created.
If another developer clones the parent repository, they can fetch the exact recorded submodule revision with:
Working Safely with Branches
Submodules often surprise people because checking out the parent repository at a specific commit can place the submodule in detached HEAD state. That behavior is normal. It means the parent repository is asking for an exact child commit, not necessarily a child branch.
Before making edits, confirm where you are:
If the branch name is blank, you are detached. Switch to the correct branch first, or create one, then continue. That small check prevents the common mistake of committing to a detached state and losing track of the new commit later.
Common Pitfalls
- Committing only in the parent repository. That records a pointer change but not the actual child changes.
- Forgetting to push the submodule commit before pushing the parent repository. Teammates then receive a pointer to a commit they cannot fetch.
- Editing the submodule on detached
HEAD. The commit may exist, but it is easy to orphan if you do not attach it to a branch. - Running
git add .at the parent root and expecting submodule file diffs. The parent tracks only the submodule reference, not the internal files. - Missing recursive initialization when cloning. A fresh clone needs
git submodule update --init --recursiveto populate the child repositories.
Summary
- A submodule change requires one commit in the submodule and one in the parent repository.
- The parent repository stores only a commit reference for the submodule.
- Push the submodule commit before sharing the parent commit.
- Check for detached
HEADinside the submodule before editing. - Use
git submodule statusandgit diff --submoduleto verify the recorded revision.

