Search code examples
gitversion-controlgit-branchgit-submodules

Git Submodule Changing Branch - unexpected behaviour


I want to pull in a great library from github into my code. As an minimum example, I'll create a new git repo so you can follow along! I arrived here because I wanted to change the branch of the siubmodule I am using, and my efforts to do this unleashed all kinds of hell on my project. So, I figured I'd jump into a sandpit while I figure it out. Here's what I see.

set up sandpit

git init
touch empty.txt
echo "nothing" > empty.txt

mkdir libs
git submodule add -b release/v3.1.x https://github.com/espressif/esp-aws-iot.git libs/esp-aws-iot
cd libs/esp-aws-iot/
git submodule update --init --recursive
cd ../..
git add .
git commit -m "initial"

status

git status
    On branch main
    nothing to commit, working tree clean

git submodule
     2f227649da036b80caa5537fbf934980df073fdf libs/esp-aws-iot (heads/release/v3.1.x)

change submodule branch to master & check status

cd libs/esp-aws-iot/
git checkout master
cd ../..
git status

On branch main
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:   libs/esp-aws-iot (new commits, untracked content)

no changes added to commit (use "git add" and/or "git commit -a")

git submodule
+d37fd63002b4fda99523e1ac4c9822fce485e76d libs/esp-aws-iot (202210.01-LTS-release-6-gd37fd63)

Hmmm. That's not what I expected to see... I want to have my submodule cleanly on the master branch.

git submodule update --remote libs/esp-aws-iot
git submodule
 2f227649da036b80caa5537fbf934980df073fdf libs/esp-aws-iot (heads/release/v3.1.x)

again, not what I had hoped for.

Another attempt

cd libs/esp-aws-iot
git branch --all
* (HEAD detached at 2f22764)
  master
  release/v3.1.x
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/release/202012.04-LTS
  remotes/origin/release/202210.01-LTS
  remotes/origin/release/beta
  remotes/origin/release/v3.1.x
git checkout master
git branch -d release/v3.1.x
git status
On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        aws-iot-device-sdk-embedded-C/

git add aws-iot-device-sdk-embedded-C
git commit -m "now I'm one commit ahead of remote!"
git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

now try to clean up again

cd ../..
git status
On branch main
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:   libs/esp-aws-iot (new commits)

no changes added to commit (use "git add" and/or "git commit -a")
git add libs/esp-aws-iot
git commit -m "submodule at master"
[main 98101e9] submodule at master
 1 file changed, 1 insertion(+), 1 deletion(-)
git status
On branch main
nothing to commit, working tree clean

All of this git spaghetti can't be correct. I sort of maybe end up where I need to be. But I'm not convinced. I'm now one commit ahead of the remote! That seems completelly wrong. But it's the only way I could figure out to shut up the untracked warnings.

This question has come up before, but as demonstrated above, many of the proposed solutions do not work.


Solution

  • Keep in mind that submodules don't point to branches. They point to commits.

    If you want to change the commit to the one currently pointed to master, you need to:

    pushd your_submodule
    git rev-parse HEAD     # not necessary, just to show the current submodule commit hash
    git checkout master    # maybe you want to do a git pull before this
    git rev-parse HEAD     # again, not necessary, only to show that the commit has changed
    
    popd                   # back to the parent repo
    git status             # you submodule should be in red
    git diff               # you may see the submodule going from the old commit to the new one
    git add your_submodule
    git commit
    

    But keep in mind what I said before: submodules don't point to branches, and your parent repo doesn't know about what its the submodule master. If the submodule master changes and if you want that new code, you'll need to do this again.

    I suggest you to read the submodule section in Pro Git: https://git-scm.com/book/en/v2/Git-Tools-Submodules. I hope it helps you!