Skip to main content

Overview

Git submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.

Nested Repositories

Include external repositories within your project

Version Pinning

Lock submodules to specific commits

Automatic Updates

GitHub Desktop handles submodule updates automatically

Recursive Operations

Clone, pull, and checkout operations include submodules

Understanding Submodules

What are Submodules?

Submodules are Git repositories embedded inside another Git repository:

When to Use Submodules

Good Use Cases:

External Dependencies

Include libraries or frameworks as source

Shared Code

Share common code between projects

Monorepo Components

Manage separate components with independent histories

Version Control

Pin dependencies to specific versions
Alternatives to Consider:
  • Package managers (npm, pip, Maven) for dependencies
  • Mono-repo tools (Lerna, Nx) for related projects
  • Git subtrees for simpler embedding

Submodule Configuration

.gitmodules File

Submodules are defined in .gitmodules:
.gitmodules
Fields:
  • path: Location in your repository
  • url: Remote repository URL
  • branch: (Optional) Branch to track

.git/config

Local configuration in .git/config:

Cloning with Submodules

GitHub Desktop automatically handles submodules when cloning:

Automatic Recursive Clone

When you clone a repository in GitHub Desktop, it automatically clones all submodules recursively using the --recursive flag.

What Happens:

1

Clone Main Repository

GitHub Desktop clones the main repository
2

Read .gitmodules

Identifies all submodules from .gitmodules
3

Initialize Submodules

Runs git submodule init for each submodule
4

Clone Submodules

Clones each submodule repository
5

Checkout Commits

Checks out the specific commit SHA recorded in the parent

Updating Submodules

GitHub Desktop automatically updates submodules during Git operations:

Update Implementation

When Submodules Update:

GitHub Desktop updates submodules after:
  1. Checkout: Switching branches
  2. Pull: Pulling changes from remote
  3. Merge: Merging branches
  4. Rebase: Rebasing branches
This ensures submodules are always at the correct commit.

Progress Tracking

GitHub Desktop shows progress when updating submodules, with a smooth exponential curve since the total count isn’t known upfront.

Viewing Submodule Status

GitHub Desktop detects submodules and their state:

Listing Submodules

Submodule Status Indicators

The first character in git submodule status output indicates:
  • (space): Submodule is checked out at the correct commit
  • -: Submodule is not initialized
  • +: Submodule is checked out to a different commit than recorded
  • U: Submodule has merge conflicts

Modifying Submodules

Updating a Submodule

To update a submodule to a newer commit:
1

Navigate to Submodule

Open terminal and cd into the submodule directory
2

Pull Changes

3

Return to Parent

4

Commit Submodule Update

In GitHub Desktop, you’ll see the submodule as modified. Commit this change to update the submodule pointer.

Resetting Submodules

Reset submodules to the recorded commit:
Use this to:
  • Discard local changes in submodules
  • Reset to the commit recorded in parent
  • Fix submodules in unexpected states

Submodule Workflows

Adding a New Submodule

Use the terminal:
GitHub Desktop will then track the submodule.

Removing a Submodule

Use the terminal:

Updating All Submodules

Update all submodules to their latest commits:
Then commit the updates in GitHub Desktop.

File Protocol Support

Some operations allow file:// URLs for submodules:
This enables:
  • Local submodules (for testing)
  • Submodules on network drives
  • Internal corporate repositories
File protocol access is restricted by default for security. GitHub Desktop enables it only when necessary.

Nested Submodules

GitHub Desktop supports submodules within submodules:
The --recursive flag ensures all levels are:
  • Cloned when cloning the parent
  • Updated when updating the parent
  • Initialized when checking out

Best Practices

Pin submodules to specific commits: Don’t rely on branch tracking. Explicitly commit the submodule SHA you want.
  1. Keep Submodules Updated
    • Regularly update to latest commits
    • Test after updating
    • Commit submodule updates separately
  2. Document Submodule Purpose
    • Add comments in .gitmodules
    • Document in README
    • Explain why it’s a submodule
  3. Avoid Modifying Submodules Directly
    • Make changes in the submodule’s repository
    • Pull updates into parent repo
    • Don’t commit directly in submodule directories
  4. Use HTTPS for Public Submodules
    • SSH URLs require key access
    • HTTPS works for everyone
    • Easier for CI/CD
  5. Initialize Before Operations
    • Always run git submodule update --init
    • GitHub Desktop does this automatically
    • Important for CI/CD scripts
  6. Consider Alternatives
    • Package managers for dependencies
    • Monorepo tools for related code
    • Subtrees for simpler workflows

Common Issues

If a submodule doesn’t update:
  • Check if it’s initialized: git submodule status
  • Update manually: git submodule update --init --recursive
  • Verify URL in .gitmodules is correct
  • Check network/authentication issues
If submodule always appears modified:
  • Submodule is at a different commit than recorded
  • Check current commit: cd submodule && git rev-parse HEAD
  • Reset to recorded: git submodule update --force
  • Or commit the new state to update the pointer
Submodules are typically in detached HEAD state:
  • This is normal behavior
  • Submodules point to specific commits, not branches
  • To make changes:
If submodules are missing after clone:
  • Initialize them: git submodule init
  • Update them: git submodule update --recursive
  • Or in one command: git submodule update --init --recursive
  • GitHub Desktop does this automatically
If submodule operations fail with auth errors:
  • Verify you have access to submodule repository
  • Check URL protocol (HTTPS vs SSH)
  • Ensure credentials are configured
  • Try updating URL in .gitmodules

Submodule Alternatives

Git Subtrees

Pros:
  • Simpler than submodules
  • No special commands needed
  • Easier for collaborators
Cons:
  • History becomes intermingled
  • Harder to contribute back upstream

Package Managers

Pros:
  • Designed for dependencies
  • Version resolution
  • Easier updates
Cons:
  • Requires package to be published
  • Less control over source

Monorepo Tools

Pros:
  • Better tooling (Lerna, Nx, Rush)
  • Shared dependencies
  • Atomic commits across projects
Cons:
  • Repository can get large
  • Requires tool adoption