How to revert a Git Submodule pointer to the commit stored in the containing repository?
Asked Answered
Z

7

178

I have a git submodule in my main git repo. As I understand it, the main repo stores a SHA value (somewhere...), pointing to the specific commit of the submodule that it is "linked to".

I went in to my submodule and typed git checkout some_other_branch. I have no idea which commit I came from.

I would like to revert that pointer so that the main repo and the submodule are in sync again.

My first (probably naive) instinct was to say git reset --hard - that seems to work for everything else. To my surprise, it did not work for this scenario.

So I've figured out that I can type git diff, note the SHA ID that the submodule pointer used to have, and then head into the submodule and git checkout [SHA ID]... but surely there must be an easier way?

As I'm still learning about git submodules, please feel free to correct my terminology if there are words for concepts that I don't know.

Zealotry answered 24/10, 2011 at 22:13 Comment(0)
G
217

You want to update your submodule so it is in sync with what the parent repository believes it should be. This is what the update command is for:

From the submodule manpage:

Update the registered submodules, i.e. clone missing submodules and
checkout the commit specified in the index of the containing
repository. This will make the submodules HEAD be detached unless
--rebase or --merge is specified or the key submodule.$name.update
is set to rebase or merge.

Run this and all should be well:

git submodule update --init

You can add the --recursive flag as well to recurse through all submodules.

Gaeta answered 24/10, 2011 at 23:28 Comment(7)
Somehow, for me I needed to add --init. Without it, the submodules would stay in a state with (new commits). Even though my submodules were already initialised.Volsung
@Volsung yes the --init option is crucial in all this. I was getting prompted for username and password since my submodules were cloned over https. I went into both folder and set the remotes to use the ssh protocol for checkout.Drinkwater
doesn't work if submodule commit hash is modified & unstagedRebekahrebekkah
can add --recursive so that you don't need to go to all the submodulesPigfish
Doesn't work for me. After git submodule update the submodule is still at some other commit (no changes in that submodule's working dir).Economical
I needed to add --init for git submodule update to do what the OP is asking for. Can you update the answer?Economical
Added --init flag and a note about --recursive.Gaeta
C
24

To change the commit that a submodule points to, you need to checkout that version in the submodule, then go back to the containing repo, add and commit that change.

Or, if you want the submodule to be on the version the top repo points to, do git submodule update --recursive. Add --init if you've just cloned.

Also, git submodule without a submodule command will show you the commit you are pointing to. There will be a - or a + in front of the commit if it's not in sync.

If you look at a tree with a submodule in it, you can see that the submodule is marked as a commit as opposed to the rest that are blobs or trees.

to see what a particular commit points wrt to submodules you can:

git ls-tree <some sha1, or branch, etc> Submodule/path

you can then see the commit or anything else if you like by passing that into log, etc (the git-dir option at the git command level allows you to skip having to cd down to the submodule):

git --git-dir=Submodule/path log -1 $(<the above statement>)
Chambertin answered 24/10, 2011 at 23:13 Comment(1)
The below command helped me (I wanted to disregard any changes in submodule and in my module also): git submodule update --init --recursiveBandwidth
B
9

Another case I just ran into is if there is an unstaged change in the submodule that you want to discard. git submodule update will not remove that change, nor will git reset --hard on the parent directory. You need to go to the submodule directory and do a git reset --hard. So if I want to fully discard unstaged changes in both my parent and submodule, I do the following:

In Parent:

git reset --hard

git submodule update

In Submodule:

git reset --hard
Braynard answered 9/4, 2017 at 5:31 Comment(1)
Running git reset --hard from within the submodule doesn't work to revert back to the commit defined in the parent repo. It just resets the working tree to whatever the HEAD of the submodule currently is.Huneycutt
T
6

Use git ls-tree HEAD in the "superproject" folder to see what commit your submodule was originally at. Then change into the submodule directory and use git log --oneline --decorate to see what branch the original commit is on. Finally, git checkout original-commit-branch.

Using some test directories I set up, here's what the commands might look like:

$ git --version
git version 1.7.4.1
$ 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)
#
#   modified:   sm2 (new commits)
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git ls-tree HEAD
100644 blob 76813a07ae558db274cefc6d903ec24323fdeb0d    .gitmodules
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    main
160000 commit 7c5889497938cd5699a9234a98ee93947e52b1ed  sm1
160000 commit f68bed61cba6f94cef57554f2cf46a45a4a0d337  sm2
$ cd sm2
$ git log --oneline --decorate
5b8d48f (HEAD, foo1) foo1.1
f68bed6 (origin/master, origin/HEAD, master) Initial commit.
$ git checkout master
Switched to branch 'master'
$ cd ..
$ git status
# On branch master
nothing to commit (working directory clean)

The "superproject" shows the sm2 submodule at commit f68bed6 but sm2 has it's HEAD at 5b8d48f. The submodule commit f68bed6 has three branches on it that may be used for checkout in the submodule directory.

Thesis answered 24/10, 2011 at 23:49 Comment(2)
THANKS DAN, PERFECTO!Gavra
BEWARE - recently github have changed name from master to main.Botulinus
T
6

The answer here somehow didn't solve my specific issue with the submodule so in case it happens to you too, try the following...

 git submodule foreach git reset --hard
Testicle answered 21/5, 2018 at 21:58 Comment(3)
nice one-liner!Asuncion
The link didn't workPhilipphilipa
this is only going to get rid of uncommitted changes in the submodule. If you have already created new commits in the submodule directory they won't be reverted back to the original containing repository commit by the reset command.Zimmer
B
6

I wanted to disregard any changes in submodule and in my module also

The below command helped me:

git submodule update --init --recursive
Bandwidth answered 16/8, 2019 at 0:59 Comment(0)
B
-1

enter image description here

An updated visual walk through - here my submodule is pointing at - 8c3fd8b It would be straightforward to go to this folder and....

git checkout master
error: pathspec 'master' did not match any file(s) known to git

In the submodule eg. stylegan2-ada folder needed to run

git checkout main
git pull

this resolved my problem (temporarily)

last step was to commit the changes in parent repo. The tracked changes appeared automatically - and I didn't need to create a file - just stage the file changes by clicking the + in vscode and pushing.

here very clearly you can see the git commits refreshing.

-Subproject commit 8c3fd8bac3e5a54a20e860fc163d6e67cc03c623
+Subproject commit 0045ea50f1b9710ffde3ab2a9a18c0d4c97bfaed

enter image description here

Troubleshooting

Beware that there's a .gitsubmodule file that points to respective git remote repo.

enter image description here

Botulinus answered 28/12, 2020 at 11:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.