Resolving Git Submodule Tracking Issues

Resolving Git Submodule Tracking Issues #

The Problem #

I recently encountered a frustrating Git issue with my Hugo blog setup. I had installed the Hugo Book theme as a Git submodule for my static site, but for some reason there were a bunch of changed files showing up in the theme’s directory even though I had never run git submodule update or made any intentional changes to it. At the time, I didn’t really understand how submodules work, so I tried adding it to .gitignore thinking that would solve the problem.

Here’s what my blog structure looked like:

[user@hugo blog]$ tree . themes/hugo-book/ -L 1 -a
.
├── archetypes
├── content
├── data
├── .git
├── .gitignore
├── .gitlab-ci.yml
├── .gitmodules
├── .hugo_build.lock
├── hugo.toml
├── i18n
├── layouts
├── .markdownlint.yaml
├── .pre-commit-config.yaml
├── public
├── resources
├── static
└── themes
themes/hugo-book/
├── archetypes
├── assets
├── exampleSite
├── .git
├── .github
├── .gitignore
├── go.mod
├── i18n
├── images
├── layouts
├── LICENSE
├── README.md
├── static
└── theme.toml

The tree command parameters explained:

  • . themes/hugo-book/ - Show both the current directory and the submodule directory
  • -L 1 - Limit depth to 1 level (only show immediate contents, not subdirectories)
  • -a - Show all files, including hidden ones (like .git, .gitignore, etc.)

Notice how both the main repository and the themes/hugo-book/ directory have their own .git directories - this is the telltale sign of a submodule being a separate Git repository.

Here’s what I was seeing which made no sense to me at the time, as I didn’t know what git submodules really are.

[user@hugo blog]$ cat .gitignore
public/
.hugo_build.lock
resources/
themes/hugo-book

[user@hugo blog]$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
  (commit or discard the untracked or modified content in submodules)
        modified:   themes/hugo-book (modified content)

no changes added to commit (use "git add" and/or "git commit -a")

This was preventing me from committing other changes to my repository.

Why .gitignore Doesn’t Work for Submodules #

The key insight here is understanding the difference between submodules and regular directories:

  • Submodules are Git repositories embedded within another Git repository
  • They are tracked in the parent repository’s .gitmodules file and have their own commit history
  • .gitignore only prevents untracked files from being added to Git
  • Since submodules are already tracked by Git, adding them to .gitignore has no effect

You can identify if a directory is a submodule by checking:

[user@hugo blog]$ git submodule status
f2c703e155881a017cabbee17224e2dfeee0498c themes/hugo-book (v11.0.0-2-gf2c703e)

You can also check the .gitmodules file which contains the submodule configuration:

[user@hugo blog]$ cat .gitmodules
[submodule "themes/hugo-book"]
        path = themes/hugo-book
        url = https://github.com/alex-shpak/hugo-book

The Root Cause #

When I investigated further, I discovered that every single file in the submodule was showing as modified:

cd themes/hugo-book
git status

There was also a Git security issue, this stems from a time when I tried installing the theme and thought it was a permissions issue… it wasn’t:

[user@hugo blog]$ git status
fatal: detected dubious ownership in repository at '/var/lib/snapd/void/blog/themes/hugo-book'

The Solution #

Step 1: Fix Git Ownership Issues #

First, I resolved the Git security warning:

git config --global --add safe.directory /var/lib/snapd/void/blog/themes/hugo-book

Step 2: Reset the Submodule #

Since I didn’t need any of the local modifications in the submodule, I reset it to the expected state:

# From the main repository root
cd /var/lib/snapd/void/blog

# Reset submodule to the exact commit expected by main repo
git submodule update --init --recursive --force

This command:

  • --force: Discards any local changes in the submodule
  • --init: Initializes the submodule if needed
  • --recursive: Handles any nested submodules
  • Resets to the specific commit hash tracked by the parent repository

Step 3: Verify the Fix #

After running the command:

[user@hugo blog]$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

This fixed the messy git submodule problem I had.