Git Submodules Workflow Guide
This document explains how to work with the LARC meta repository and its submodules effectively.
Repository Structure
larc/ (meta repo)
├── apps/ (submodule -> github.com/larcjs/apps)
│ ├── components/ (nested submodule -> github.com/larcjs/components)
│ └── core/ (nested submodule -> github.com/larcjs/core)
├── site/ (submodule -> github.com/larcjs/site)
├── core/ (submodule -> github.com/larcjs/core)
├── ui/ (submodule -> github.com/larcjs/components)
├── examples/ (submodule -> github.com/larcjs/examples)
├── devtools/ (submodule -> github.com/larcjs/devtools)
├── components-types/ (submodule)
└── core-types/ (submodule)
Understanding Git Submodules
The Key Concept
A submodule reference is just a pointer to a specific commit SHA in another repo.When the meta repo has changes like:
modified: apps (new commits)
This means the apps submodule has moved to a different commit than what the meta repo expects.
Why Detached HEAD?
When you enter a submodule directory, git checks out the exact commit SHA that the parent repo points to, not a branch. This is by design to ensure reproducibility. You're in "detached HEAD" state because you're viewing a specific point in history, not following a branch.Essential Commands
1. Pulling Latest Updates (All Repos)
Use the provided script:
# From meta repo root
./pull-updates.sh
Or manually:
# Pull meta repo
git pull
# Update all submodules to their latest remote main branches
git submodule update --init --recursive --remote
# OR use the combined command
git pull --recurse-submodules && git submodule update --init --recursive --remote
What this does:
- Pulls latest changes in the meta repo
- Updates ALL submodules (including nested ones) to their latest remote
mainbranch - Initializes any new submodules that were added
Common Workflows
Workflow 1: Making Changes to a Submodule (e.g., apps, components)
Scenario: You want to edit files inapps/ or apps/components/
#### Step 1: Enter the submodule and switch to a branch
cd apps
git checkout main # Get off detached HEAD!
git pull # Get latest changes
#### Step 2: Make your changes and commit
# Edit files...
git add .
git commit -m "Your commit message"
#### Step 3: Push your changes to the submodule's remote
git push origin main
#### Step 4: Update the meta repo to point to your new commit
cd .. # Back to meta repo root
git add apps
git commit -m "Update apps submodule to latest version"
git push
Important: The meta repo must be updated to "know" about the new commit in the submodule!
Workflow 2: Making Changes to Nested Submodules (e.g., apps/components)
Scenario: You want to editapps/components/
#### Step 1: Navigate to nested submodule and switch to branch
cd apps/components
git checkout main
git pull
#### Step 2: Make changes and commit
# Edit files...
git add .
git commit -m "Enhance components"
git push origin main
#### Step 3: Update the parent submodule (apps)
cd .. # Now in apps/
git add components
git commit -m "Update components submodule to latest version"
git push origin main
#### Step 4: Update the meta repo
cd .. # Now in meta repo root
git add apps
git commit -m "Update apps submodule (which includes updated components)"
git push
You must update TWO levels: first the intermediate repo (apps), then the meta repo.
Workflow 3: Syncing Production with Latest Changes
Scenario: You've pushed changes to submodule repos and want production to get them.#### On your production server:
cd /path/to/larc
./pull-updates.sh
# Verify everything is on correct branches
git submodule foreach --recursive 'git checkout main || true'
Workflow 4: Someone Else Updated a Submodule
Scenario: A teammate pushed changes toapps or components.
#### Step 1: Pull meta repo
git pull
You'll see:
modified: apps (new commits)
#### Step 2: Update submodules
git submodule update --init --recursive
This checks out the exact commits the meta repo now points to.
Optional: If you want submodules on theirmain branches:
git submodule foreach --recursive 'git checkout main && git pull'
Preventing Detached HEAD Issues
Always Work on Branches
When you enter a submodule to make changes:cd apps
git checkout main # DO THIS FIRST!
Create a Helper Script
Creatework-on-submodule.sh:
#!/bin/bash
# Usage: ./work-on-submodule.sh apps
SUBMODULE=$1
cd "$SUBMODULE" || exit 1
git checkout main
git pull
echo "Ready to work on $SUBMODULE (on main branch)"
Quick Reference Commands
Status Check
# See which submodules have uncommitted changes or are on different commits
git status
# See status of all submodules
git submodule status
# Recursively check status of nested submodules
git submodule foreach --recursive 'echo "=== $name ===" && git status'
Fix Detached HEAD
# If you're in a submodule in detached HEAD:
git checkout main
git pull
View Submodule Changes
# See which commit the submodule moved to
git diff apps
# See the actual code changes in a submodule
cd apps && git log
Update Single Submodule
# Update just one submodule to its latest remote main
git submodule update --remote apps
Best Practices
1. Always commit submodule changes first, meta repo second
# ❌ WRONG ORDER
cd meta-repo
git add apps
git commit -m "Update apps" # But apps changes aren't pushed yet!
# ✅ CORRECT ORDER
cd apps
git push # Push submodule changes first
cd ..
git add apps
git commit -m "Update apps" # Then update meta repo pointer
git push
2. Use descriptive commit messages in meta repo
# ❌ Vague
git commit -m "Update submodules"
# ✅ Descriptive
git commit -m "Update apps submodule to include new routing features"
3. Verify before pushing
# Check submodule commits are pushed
cd apps && git log origin/main..HEAD # Should be empty
cd ../site && git log origin/main..HEAD # Should be empty
# Then push meta repo
cd .. && git push
4. Document nested submodule changes
When updating nested submodules, your commit chain should be:apps/components with message about component changesapps with message "Update components submodule: [reason]"Troubleshooting
"I'm stuck in detached HEAD!"
git checkout main
git pull
"My changes are missing after submodule update!"
If you made commits while in detached HEAD, they're not lost:git reflog # Find your commit SHA
git checkout main
git cherry-pick <commit-sha> # Apply your changes to main
"Submodule conflicts after pull"
# Option 1: Take remote version
git submodule update --init --recursive --remote
# Option 2: Keep your version (don't update submodules)
git submodule update --init --recursive
# Option 3: Manually resolve
cd problem-submodule
git checkout main
git pull
cd ..
git add problem-submodule
"I can't push - authentication failed"
Check your git remote URL:git remote -v
If it shows https://github.com/..., you may need to:
git@github.com:...Automation Tips
Git Aliases
Add to~/.gitconfig:
[alias]
sup = submodule update --init --recursive --remote
spull = !git pull && git submodule update --init --recursive --remote
spush = push --recurse-submodules=on-demand
Usage:
git spull # Pull everything
git spush # Push with submodule safety check
Pre-commit Hook
Create.git/hooks/pre-commit in meta repo:
#!/bin/bash
# Check if any submodule has unpushed commits
git submodule foreach --quiet --recursive '
if [ $(git log origin/$(git rev-parse --abbrev-ref HEAD)..HEAD --oneline | wc -l) -gt 0 ]; then
echo "Error: Submodule $name has unpushed commits!"
exit 1
fi
'
Summary Cheatsheet
| Action | Commands |
|--------|----------|
| Pull all updates | ./pull-updates.sh |
| Work on submodule | cd apps && git checkout main |
| Commit submodule change | git add . && git commit && git push |
| Update meta repo pointer | cd .. && git add apps && git commit -m "Update apps" |
| Fix detached HEAD | git checkout main |
| Check all status | git submodule foreach --recursive git status |
| Sync to specific commit | git submodule update --init --recursive |
| Sync to latest remote | git submodule update --init --recursive --remote |
Deploy to Production Checklist
- [ ] All submodule changes committed and pushed
- [ ] Meta repo updated to point to new submodule commits
- [ ] Meta repo changes pushed
- [ ] On production server:
git pull - [ ] On production server:
./pull-updates.sh - [ ] Verify:
git submodule statusshows expected commits - [ ] Test application functionality
Last updated: 2025-12-06