Skip to main content

/git-submodule-commit-all - Bottom-Up Submodule Commit & Push

Bottom-up commit and push across all dirty submodules, update parent pointers, and run recursive init.

Usage

/git-submodule-commit-all                # Full workflow: commit, push, init
/git-submodule-commit-all --dry-run # Preview what would be committed
/git-submodule-commit-all --init-only # Skip commits, just run recursive init
/git-submodule-commit-all --fix-orphans # Also detect and fix orphaned entries

Options

OptionDescription
--dry-runShow dirty submodules and changes without committing
--init-onlyOnly run git submodule update --init --recursive
--fix-orphansDetect and fix orphaned submodule entries
--no-pushCommit but don't push
--no-initSkip recursive init after committing

System Prompt

EXECUTION DIRECTIVE:

When the user invokes /git-submodule-commit-all, execute this 6-step workflow:

Step 1: Discover Dirty Submodules

# Find submodules with new commits (pointer updates needed)
git submodule status 2>&1 | grep '^\+'

# Find submodules with modified/untracked content
git status --short | grep '^ [mM]'

Categorize each submodule:

  • New commits (+ prefix in git submodule status) - needs pointer update in parent
  • Modified content - has uncommitted changes inside the submodule working tree
  • Untracked content - has untracked files inside

If --dry-run, display the list and stop.

Step 2: Commit & Push Each Dirty Submodule (Bottom-Up)

For each submodule with new commits or modified content:

REPO="path/to/submodule"

# Ensure on main branch
git -C "$REPO" checkout main 2>/dev/null

# Check for uncommitted changes
git -C "$REPO" status --short

# If changes exist, stage and commit
git -C "$REPO" add -A
git -C "$REPO" commit -m "chore: <describe changes>"

# Push to remote
git -C "$REPO" push

Commit message generation: Inspect git -C "$REPO" diff --cached --stat to generate a descriptive message.

Handle index.lock: If fatal: Unable to create index.lock, kill the holding process and remove the lock file.

Step 3: Stage Submodule Pointer Updates in Parent

# Add all submodules with new commits
git add submodules/path/to/each/dirty/submodule

# Also add any directly modified files in parent repo
git add other-changed-files

Step 4: Commit & Push Parent Repo

git commit -m "chore(submodules): update N submodule pointers

- submodule1: brief description
- submodule2: brief description

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"

git push

Pre-commit hooks: If markdownlint or other hooks fail, auto-fix and retry.

Step 5: Recursive Init

git submodule update --init --recursive

Verify no errors:

git submodule update --init --recursive 2>&1 | grep -i "fatal\|error"
# Expected: no output

Step 6: Fix Orphaned Entries (if --fix-orphans)

Detect entries in git tree but missing from .gitmodules:

git ls-tree -r HEAD | grep '^160000' | awk '{print $4}' | sort > /tmp/tree.txt
git config --file .gitmodules --get-regexp 'submodule\..*\.path' | awk '{print $2}' | sort > /tmp/mods.txt
comm -23 /tmp/tree.txt /tmp/mods.txt

For each orphaned entry:

  1. Check if the GitHub repo exists: gh repo view org/name --json url
  2. If exists: git submodule add --force <url> <path>
  3. If not: git rm <path> and commit the removal
  4. Propagate pointer updates through nested chains if needed

Final Verification

git status
# Expected: "nothing to commit, working tree clean" (submodules may show modified content)

Success Output

/git-submodule-commit-all

Step 1: Discovered 6 dirty submodules
+ cloud-backend (new commits)
+ cloud-frontend (new commits)
M coditect-core (modified content)
...

Step 2: Committed & pushed 6 submodules
cloud-backend -> 18160a2 (pushed)
cloud-frontend -> 7b821f8 (pushed)
...

Step 3: Staged pointer updates in parent

Step 4: Committed & pushed parent
b3d5e724 chore(submodules): update 6 submodule pointers

Step 5: Recursive init
68 submodules initialized, 0 errors

COMPLETE: All submodules committed, pushed, and initialized.

Failure Indicators

This command has FAILED if:

  • Submodule commit fails (merge conflicts, permission denied)
  • Push rejected (force push not allowed, auth failure)
  • Parent commit blocked by pre-commit hooks that can't be auto-fixed
  • Recursive init produces fatal: errors
  • Orphaned entries remain after --fix-orphans

When NOT to Use

  • Single submodule change - use /git-sync or manual commit instead
  • Only need init - use --init-only flag or run git submodule update --init --recursive directly
  • Read-only submodules - pointer updates only, no submodule commits needed

Version: 1.0.0 Created: 2026-02-01 Author: CODITECT Core Team