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
.gitmodulesfile and have their own commit history .gitignoreonly prevents untracked files from being added to Git- Since submodules are already tracked by Git, adding them to
.gitignorehas 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.