What is a Git Submodule?
A Git submodule allows one Git repository to contain another Git repository as a child.
Instead of storing the files of the child repository, the parent repository stores a pointer to a specific commit of the child repository.
Example:
ExternBrain/
├── Capture/
├── Evergreen/
└── Publish/ <-- Separate Git repositorymyproject.git
└── Tracks:
Publish -> commit a74f2eeThe parent repository does not contain the files of Publish.
It only remembers:
Publish should be at commit a74f2eeWhy Use a Submodule?
Without Submodule
ExternBrain/
├── Capture/
├── Evergreen/
└── Publish/Everything belongs to one repository.
Pros:
- Simpler
Cons:
-
Public notes mixed with private notes
-
Harder to publish separately
-
History becomes mixed
With Submodule
ExternBrain/
├── Capture/
├── Evergreen/
└── Publish/
└── .gitRepositories:
myproject.git
publishednotes.gitPros:
-
Clean separation
-
Independent histories
-
Easier publishing
-
Easier backup strategy
How Git Stores a Submodule
Check:
git ls-files --stage PublishExample:
160000 a74f2ee... PublishMeaning:
160000 = Gitlink (Submodule)Unlike normal files:
100644 file.txtThe parent repository stores:
Publish -> a74f2ee.gitmodules
Git stores submodule configuration in:
.gitmodulesExample:
[submodule "Publish"]
path = Publish
url = git@gitlab.com:domain/publishednotes.gitView:
cat .gitmodulesCommon Commands
Show Submodules
git submodule statusExample:
a74f2ee PublishClone Repository With Submodules
Recommended:
git clone --recurse-submodules \
git@gitlab.com:domain/myproject.gitResult:
ExternBrain/
└── Publish/automatically populated.
Initialize Missing Submodules
If cloned without --recurse-submodules:
git submodule update --init --recursiveGit reads .gitmodules and clones the missing repositories.
Update Submodules
git submodule update --recursiveSynchronizes submodules to the commits recorded by the parent repository.
Daily Workflow
Modify Publish
cd PublishMake changes.
git add .
git commit -m "Add SPI note"
git pushUpdate Parent Repository
Go back:
cd ..Check status:
git statusExample:
modified: PublishThis means:
Publish moved to a newer commit.Commit the new pointer:
git add Publish
git commit -m "Update Publish submodule pointer"
git pushImportant Rule
Always commit in this order:
1. Commit inside submodule
2. Push submodule
3. Commit parent repository pointer
4. Push parent repositoryCurrent ExternBrain Setup
ExternBrain/
├── Capture
├── Evergreen
└── PublishRepositories:
myproject.git
└── tracks
Publish -> commit XXXXXXX
publishednotes.git
└── contains published notesPublication pipeline:
Obsidian
↓
ExternBrain
↓
Publish (submodule)
↓
Quartz Build
↓
notes.domain.comTroubleshooting
Parent Shows “modified: Publish”
Example:
modified: Publish (modified content)Cause:
Something changed inside Publish.Fix:
cd Publish
git statusCommit or discard changes.
Then:
cd ..
git add Publish
git commit -m "Update submodule pointer"Clone Missing Publish Content
Symptoms:
Publish/
emptyFix:
git submodule update --init --recursiveUseful Commands Cheat Sheet
# Show submodules
git submodule status
# Clone with submodules
git clone --recurse-submodules <repo>
# Initialize submodules
git submodule update --init --recursive
# Enter Publish
cd Publish
# Commit Publish changes
git add .
git commit -m "message"
git push
# Commit updated pointer in parent
cd ..
git add Publish
git commit -m "Update Publish submodule pointer"
git push
# Inspect submodule metadata
cat .gitmodules
# Verify gitlink
git ls-files --stage Publish