GitWorktree.org logoGitWorktree.org

Git Worktree with Submodules

Using git worktree in a repository that contains submodules requires extra steps. Worktrees do not automatically initialize submodules, which is the most common source of confusion. This guide explains how it works and how to avoid the pitfalls.

How Submodules Work in Worktrees

When you run git worktree add, Git creates a new working directory and checks out the specified branch. However, it does not automatically initialize or update submodules in the new worktree. The submodule directories will exist but they will be empty.

This happens because submodule state is tracked per-worktree. Each worktree maintains its own checkout of each submodule independently. The submodule Git directories are stored under .git/modules/ in the main repository, and new worktrees need to be told to link to them.

Submodule state in a new worktree
# Main repo structure with submodules
myapp/
├── .git/
│   └── modules/           # submodule Git databases live here
│       └── libs/
│           └── shared/
├── .gitmodules            # submodule configuration (tracked)
├── src/
└── libs/
    └── shared/            # submodule working directory (populated)

# New worktree — submodule directory is EMPTY
myapp-feature/
├── .git                   # file pointing to main repo
├── .gitmodules            # present (tracked file)
├── src/
└── libs/
    └── shared/            # EMPTY — not initialized yet

Initializing Submodules in a New Worktree

After creating a worktree, you must explicitly initialize and update the submodules. There are two approaches depending on your Git version.

Standard approach (all Git versions)

Initialize submodules manually
# 1. Create the worktree
git worktree add ../myapp-feature feature/auth

# 2. Enter the worktree
cd ../myapp-feature

# 3. Initialize and update all submodules
git submodule update --init --recursive

One-liner with a shell helper

Shell helper for worktree + submodules
# Add to ~/.bashrc or ~/.zshrc
gwt() {
  git worktree add "$@" && cd "$1" && git submodule update --init --recursive
}

# Usage
gwt ../myapp-feature feature/auth

The --recursive flag ensures nested submodules (submodules within submodules) are also initialized.

Common Issues

“Submodule not initialized” errors

If you see errors like fatal: no submodule mapping found in .gitmodules or build failures due to missing submodule files, the fix is almost always to run git submodule update --init inside the worktree.

Diagnosing uninitialized submodules
# Check submodule status (shows '-' prefix for uninitialized)
$ git submodule status
-abc1234 libs/shared (heads/main)

# The '-' prefix means the submodule is not initialized
# Fix it:
git submodule update --init --recursive

Submodule points to wrong commit

Each branch can pin a submodule to a different commit. After switching branches in a worktree or creating a worktree from a different branch, make sure to update the submodule to the correct commit.

Updating submodule commits
# Update submodules to match the current branch's recorded commits
git submodule update --recursive

# If you also want to pull the latest changes within each submodule
git submodule update --remote --recursive

Submodule directory already exists error

In some Git versions, you may see an error if the submodule metadata in .git/modules/ already exists from a previous worktree. This usually resolves itself with a fresh git submodule update --init, but if it persists:

Fixing metadata conflicts
# Deinit the submodule first, then re-init
git submodule deinit libs/shared
git submodule update --init libs/shared

Best Practices

  • Always run git submodule update --init --recursive after creating a new worktree. Make it part of your muscle memory or automate it with a shell helper.
  • Use a post-checkout hook to automatically initialize submodules. Create .git/hooks/post-checkout in your main repo and it will run in all worktrees since hooks are shared.
  • Keep submodule counts low. Each submodule adds setup time per worktree. If you have many submodules, consider whether some could be replaced with a package manager dependency instead.
  • Document the workflow. If your project uses both submodules and worktrees, add setup instructions to your README so contributors know to initialize submodules in each worktree.
  • Test your CI in a worktree. If CI clones with --recurse-submodules, verify that your build also works from a worktree where submodules were initialized manually. This catches issues with hardcoded paths.

Related Guides