It’s because Git records which commit (not a branch or a tag, exactly one commit represented in SHA-1 hash) should be checked out for each submodule. If you change something in submodule dir, Git will detect it and urge you to commit those changes in the top-level repoisitory.
git diff in the top-level repository to show what has actually changed Git thinks. If you’ve already made some commits in your submodule (thus “clean” in submodule), it reports submodule’s hash change.
$ git diff diff --git a/src/repo b/src/repo index b0c86e2..a893d84 160000 --- a/src/repo +++ b/src/repo @@ -1 +1 @@ -Subproject commit b0c86e28675c9591df51eedc928f991ca42f5fea +Subproject commit a893d84d323cf411eadf19569d90779610b10280
Otherwise it shows
-dirty hash change which you cannot stage or commit in the top-level repository.
git status also claims submodule has untracked/modified content.
$ git diff diff --git a/src/repo b/src/repo --- a/src/repo +++ b/src/repo @@ -1 +1 @@ -Subproject commit b0c86e28675c9591df51eedc928f991ca42f5fea +Subproject commit b0c86e28675c9591df51eedc928f991ca42f5fea-dirty $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) (commit or discard the untracked or modified content in submodules) modified: src/repo (untracked content) no changes added to commit (use "git add" and/or "git commit -a")
To update which commit records should be checked out for the submodule, you need to git commit the submodule in addition to committing the changes in the submodule:
git add src/repo
I just ran into this same class of problem, and I was able to use the solution offered by @AugustinAmenabar in the comments section of the accepted answer. My setup was a bit more complex, so I added the
--recursive flag to bring all dependencies up to date.
git submodule update --recursive src/repo
None of the answers here solve my problem.
I am documenting/sharing here what worked for me. Hoping it helps someone else.
Initially my submodule was at commit A (at the time of adding submodule to main repo), then I checked out a branch (let us call it
new-submodule-branch) and made commits B and C to it and pushed it to remote (github.com)
Post this, my main repo started showing
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) modified: <submodule_name> (new commits)
If, from the main repo root, I ran
git submodule update --remote --init --recursive, it kept reverting my submodule’s HEAD in detached state to commit A
So then I set the branch value as
<MainRepo>/.gitmodules as follows
[submodule "<submodule_name>"] path = <submodule_name> url = firstname.lastname@example.org:ProProgrammer/<submodule_name>.git branch = new-submodule-branch
post this, when I ran
git submodule update --remote --init --recursive, it would no longer revert my submodule’s HEAD in detached state to commit A however it still kept showing the annoying
modified: <submodule_name> (new commits)
So far, I was following the official git reference for submodules, now I decided to do some more Googling, and I stumbled an article titled Getting git submodule to track a branch, this clearly said
You have to go and update that submodule commit reference to the latest code in the remote branch to avoid this
So finally, I did what I was trying to avoid:
git add <submodule_name> git commit --amend --no-edit # I combined this with the previous commit where I added the 'branch' value in .gitmodules
If you want to see what this looks like once pushed to remote (github.com in my case), you can see this exact commit here