Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git diff says subproject is dirty

People also ask

What is a dirty submodule?

It means the same as with a non-submodule: "dirty" means the index differs from HEAD and/or the work-tree differs from the index. Each submodule is its own repository, so to test if a submodule is dirty, "cd" into the submodule and test whether the repository is dirty.

What is subproject in git?

A git submodule is a record within a host git repository that points to a specific commit in another external repository. Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated.

What is git dirty?

According to the official Git documentation, in the section on Stashing, a dirty state is defined as ... the dirty state of your working directory — that is, your modified tracked files and staged changes . From this definition, files staged for commit are dirty as well.


Update Jan. 2021, ten years later:

"git diff"(man) showed a submodule working tree with untracked cruft as Submodule commit <objectname>-dirty, but a natural expectation is that the "-dirty" indicator would align with "git describe --dirty"(man), which does not consider having untracked files in the working tree as source of dirtiness.
The inconsistency has been fixed with Git 2.31 (Q1 2021).

See commit 8ef9312 (10 Nov 2020) by Sangeeta Jain (sangu09).
(Merged by Junio C Hamano -- gitster -- in commit 0806279, 25 Jan 2021)

diff: do not show submodule with untracked files as "-dirty"

Signed-off-by: Sangeeta Jain

Git diff reports a submodule directory as -dirty even when there are only untracked files in the submodule directory.
This is inconsistent with what git describe --dirty(man) says when run in the submodule directory in that state.

Make --ignore-submodules=untracked the default for git diff(man) when there is no configuration variable or command line option, so that the command would not give '-dirty' suffix to a submodule whose working tree has untracked files, to make it consistent with git describe --dirty that is run in the submodule working tree.

And also make --ignore-submodules=none the default for git status(man) so that the user doesn't end up deleting a submodule that has uncommitted (untracked) files.

git config now includes in its man page:

By default this is set to untracked so that any untracked submodules are ignored.


Original answer (2011)

As mentioned in Mark Longair's blog post Git Submodules Explained,

Versions 1.7.0 and later of git contain an annoying change in the behavior of git submodule.
Submodules are now regarded as dirty if they have any modified files or untracked files, whereas previously it would only be the case if HEAD in the submodule pointed to the wrong commit.

The meaning of the plus sign (+) in the output of git submodule has changed, and the first time that you come across this it takes a little while to figure out what’s going wrong, for example by looking through changelogs or using git bisect on git.git to find the change. It would have been much kinder to users to introduce a different symbol for “at the specified version, but dirty”.

You can fix it by:

  • either committing or undoing the changes/evolutions within each of your submodules, before going back to the parent repo (where the diff shouldn't report "dirty" files anymore). To undo all changes to your submodule just cd into the root directory of your submodule and do git checkout .

dotnetCarpenter comments that you can do a: git submodule foreach --recursive git checkout .

  • or add --ignore-submodules to your git diff, to temporarily ignore those "dirty" submodules.

New in Git version 1.7.2

As Noam comments below, this question mentions that, since git version 1.7.2, you can ignore the dirty submodules with:

git status --ignore-submodules=dirty

To ignore all untracked files in any submodule use the following command to ignore those changes.

git config --global diff.ignoreSubmodules dirty

It will add the following configuration option to your local git config:

[diff]
  ignoreSubmodules = dirty

Further information can be found here


Also removing the submodule and then running git submodule init and git submodule update will obviously do the trick, but may not always be appropriate or possible.


EDIT: This answer (and most of the others) are obsolete; see Devpool's answer instead.


Originally, there were no config options to make "git diff --ignore-submodules" and "git status --ignore-submodules" the global default (but see also Setting git default flags on commands). An alternative is to set a default ignore config option on each individual submodule you want to ignore (for both git diff and git status), either in the .git/config file (local only) or .gitmodules (will be versioned by git). For example:

[submodule "foobar"]
    url = [email protected]:foo/bar.git
    ignore = untracked

ignore = untracked to ignore just untracked files, ignore = dirty to also ignore modified files, and ignore = all to ignore also commits. There's apparently no way to wildcard it for all submodules.


I ended up removing the submodule directory and initializing it once again

cd my-submodule
git push
cd ../
rm -rf my-submodule
git submodule init
git submodule update