git
gitignore
submodules
version control
software development

.gitignore files added inside Git submodules

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A Git submodule is a separate Git repository nested inside another repository. That separation is the key to understanding ignore behavior: the parent repository does not control which files a submodule tracks internally. Ignore rules inside a submodule belong to the submodule repository, not to the superproject.

Why the Parent .gitignore Does Not Reach Inside

When a repository contains a submodule, the parent repository tracks the submodule as a special entry that points to a specific commit. It does not track the submodule's individual files directly.

That means a .gitignore file in the parent project affects paths that belong to the parent repository, but not the internal file set of the submodule.

A structure like this helps make the boundary clear:

text
1main-repo/
2  .gitignore
3  app/
4  vendor/lib-a/   # submodule
5    .gitignore
6    src/

The parent .gitignore can ignore app/build/ or tmp/ in main-repo, but it cannot decide whether vendor/lib-a/generated.txt is ignored inside lib-a. That decision belongs to the submodule's own Git metadata.

Ignore Files in the Submodule Itself

If you want a file inside the submodule to be ignored by Git, you must add the rule in the submodule repository.

For example, from inside the submodule:

bash
cd vendor/lib-a
echo "build/" >> .gitignore
git status

Now Git evaluates build/ according to vendor/lib-a/.gitignore, because vendor/lib-a is its own repository.

If the ignore rule should be shared with everyone using the submodule, commit that .gitignore change in the submodule repository:

bash
git add .gitignore
git commit -m "Ignore generated build output"

Then update the superproject to point at the new submodule commit:

bash
cd ..
git add vendor/lib-a
git commit -m "Update lib-a submodule"

That two-step commit flow is normal for submodules.

Ignore Local-Only Files Without Changing the Submodule Repo

Sometimes you do not want to modify the shared .gitignore in the submodule. Maybe the ignored file is local to your workstation. In that case, use the submodule's local exclude file:

bash
cd vendor/lib-a
echo ".env.local" >> .git/info/exclude
git status

.git/info/exclude behaves like a local ignore file that is not committed. It is useful for editor files, machine-specific build output, or temporary artifacts that only exist in one developer environment.

This is usually better than editing a committed .gitignore if the ignore rule should not be shared with the team.

What the Superproject Actually Sees

From the parent repository's perspective, the submodule is mostly one tracked entry. The superproject notices when the submodule's checked-out commit changes, and it can also show that the submodule has uncommitted changes inside it.

A typical status in the parent repository might look like this:

bash
git status

Output often includes something conceptually like this:

text
modified: vendor/lib-a (new commits)

or this:

text
modified: vendor/lib-a (modified content)

That does not mean the parent repository is tracking each file inside the submodule. It means Git sees that the submodule repository is not in the clean state expected by the superproject.

Useful Configuration for Dirty Submodules

If local changes inside a submodule create too much noise in the parent repository, Git can be configured to reduce how aggressively it reports them.

For example:

bash
git config submodule.vendor/lib-a.ignore dirty

This tells the superproject to ignore uncommitted changes when reporting that submodule's state. It does not change how the submodule itself tracks files. It only changes what the parent repository reports.

That is a visibility setting, not an ignore rule in the normal .gitignore sense.

Common Pitfalls

The most common mistake is adding a pattern to the parent .gitignore and expecting it to ignore files inside the submodule repository. Another is changing the submodule's .gitignore but forgetting to commit that change inside the submodule and then update the recorded submodule commit in the parent repository. Teams also sometimes use .git/info/exclude when the rule should actually be shared, which leaves other developers with the same noisy files. A final issue is confusing submodule.<name>.ignore configuration with real ignore rules, even though it only affects how the superproject reports submodule dirtiness.

Summary

  • A submodule is a separate Git repository with its own ignore rules.
  • The parent repository's .gitignore does not control files inside the submodule.
  • Shared ignore rules belong in the submodule's committed .gitignore.
  • Local-only ignore rules belong in the submodule's .git/info/exclude.
  • The superproject tracks the submodule commit and can report dirty state, but it does not directly manage the submodule's internal tracked files.

Course illustration
Course illustration

All Rights Reserved.