Git status correctness with submodules

Viewed 47

I just added mysql-server as a submodule to my project.

Then I switch from the current "master" to the release I will be using for my development with

git checkout tags/mysql-8.0.27

Now, before committing I tried to see what I'm about to commit.

Turns out I will push .gitmodules, mysql-server/ and then I see:

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:   mysql-server (new commits)

Why is that? Will this be gone after committing? Or I should add this to the staging?

Please advise.

EDIT:

Just to clear things up.

In my repository I did:

ls -la                          # toget the list of stuff
git submodule add mysql-server # full URL skipped for clarity
cd mysql-server                 # nothing committed as of yet and nothing is added to commit
git checkout tags/mysql-8.0.27  # this checkout last commit in the 8.0.27 series
cd ..                           # I'm ready to add and commit because I want to work with that specific TAG
git status

At this point I see 2 things in the staging - .gitmodules and mysql-server directory. AND I also see the mysql-server directory with the message above.

After performing those commands I see in the status:

$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    new file:   .gitmodules
    new file:   mysql-server

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:   mysql-server (new commits)
1 Answers

Edit: the fact that you ran this git checkout in the submodule is crucial information. I assumed you ran this git checkout in the superproject. Most of the original answer is therefore wrong; let me revise it. I'll leave it in since the original question still implies the original answer.

New answer

You now say that you ran:

git submodule add <url> mysql-server

in your superproject, and then ran git checkout tags/mysql-8.0.27 in the submodule. Using your updated question and some comments below, I have created a minimal reproducible example as follows:

#! /bin/sh -e

# create reproducer repo; create an initial commit
# and make the branch name be "master" for consistency
# with the original question.
mkdir repro
cd repro
git init
echo test submodule example on stackoverflow > README
git add README
git commit -m initial
git branch -m master

# add submodule, using its current master/main/whatever branch
# as the commit to be selected
git submodule add https://github.com/mysql/mysql-server.git mysql-server 

# switch the submodule to the commit selected by tag mysql-8.0.27
(cd mysql-server && git checkout tags/mysql-8.0.27)

# observe status
git status

Running this produces (I've snipped various sections for brevity, replacing them with ...):

Initialized empty Git repository in ...
...
Updating files: 100% (8402/8402), done.
Note: switching to 'tags/mysql-8.0.27'.

You are in 'detached HEAD' state. ...

HEAD is now at 3290a66c89e 
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .gitmodules
        new file:   mysql-server

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:   mysql-server (new commits)

If you'd like your superproject to record this as the desired commit, you simply need to move back to the superproject and run:

git add mysql-server

to update the gitlink in the index/staging-area for the superproject, and then git commit to store the .gitmodules and chosen gitlink hash ID in a new commit. Since my script leaves me above the superproject, I did that by hand like this:

$ cd repro
$ git add mysql-server
$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
    new file:   .gitmodules
    new file:   mysql-server

$ [master c472e53] add myqsl-server submodule using v8.0.27
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 mysql-server

Cloning and checking out the superproject (with --recursive to also clone and check out the submodule, or followed by git submodule update --init) will also clone and check out the tags/mysql-8.0.27 commit in the submodule.

Original question's answer

git checkout tags/mysql-8.0.27

Since you didn't run git checkout --recursive (and presumably don't have recursive checkout set as your default either), this updated your current commit in your superproject only.

The commit you selected (via tags/mysql-8.0.27) calls for some particular submodule commit. I don't know the actual hash ID; let me make up a fake one. I'll say that it calls for b777777. (It's possible that it does not call for any; in that case, you'll have to decide whether "remove the submodule entirely" is the correct thing, or "add the submodule" is the correct thing.)

Earlier, when you set up the submodule, you cloned and checked out some commit. I don't know the actual hash ID; let me make up a fake one. I'll say that you currently have a123456 checked out in the submodule.

Well, you still have a123456 checked out in the submodule. That is, after all, a completely different Git repository. Sure, it's a submodule. But that just means that the superproject will look at it now and then. It was, is, and always will be a completely different Git repository, with its own commits and branch and tag names and checkout and so on.

The superproject is now calling for some particular commit. The submodule isn't on that commit. So git status, run in the superproject, says:

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:   mysql-server (new commits)

which means "the submodule is not on the commit that the superproject says it should be on".

Who's right? Who's wrong? Which commit should the submodule be on? That's for you to decide. You pick the right commit. You can use the hash ID called for by the superproject. You can use the hash ID that's in the submodule right now. You can run git log in the submodule and poke around until you find some particular commit you like. Pick some commit and run *git checkout hash-id and you now have that commit checked out in the submodule.

The superproject's commit calls for some hash ID (I made it up above, let's repeat it now: b777777). You could pick that one and git checkout b777777 (but of course b777777 is probably not the right hash ID, and might not even be a valid one, since I made it up). If you do check out that particular commit, as the superproject commit asks you to, git status run in the superproject Git repository will stop saying this thing about the submodule.

If that's not the right commit, though, it's up to you to find the right commit, and check that one out. You can then git add the submodule path in the superproject, to record what is the right hash ID (according to whatever process you used to determine that), and run git commit in the superproject to make a new commit that calls for that hash ID.

If the superproject already calls for the right hash ID, use git checkout in the submodule with that hash ID. Or have Git do it for you, with any of these:

git submodule update

or:

git rev-parse :mysql-server

(a commit hash ID will pop out) and then:

(cd mysql-server && git checkout <hash-id>)

(put in the hash ID that came out from the git rev-parse), or:

git checkout --recursive tags/mysql-8.0.27

(this has your superproject Git run git submodule update --recursive for you; that's all the --recursive really does here).

git submodule status is sometimes helpful too

Consider running git submodule status to see both the current and called-for commit, for each submodule listed in the superproject. Consider running git submodule summary as well. The information these dump out is in Git's usual cryptic form, unfortunately, and submodules are called sob-modules for good reason. But that's basically it: it's all about figuring out which commit to use from each submodule.

Related