infoclogged
infoclogged

Reputation: 3997

Git Submodule : Cannot update submodule to an earlier revision

I have spent a lot of time in reading and trying out git submodules. But I have really given up.

My problem:

I am cloning a git repository as a submodule. So, I do

git submodule add -b master url localpath

The repository starts downloading and a corresponding entry is made in the .gitmodules file. git submodule status shows the latest commit.

So far so good.

During the development, it was found out that the HEAD commit in the submodule has a bug. So, the commit should be changed from master to some commit id.

So, I changed the commit id ( 7 aplhanumeric ) in the .gitmodule file from branch = master

branch = <commitid> -> .gitmodule file

And did

git submodule update --remote

The error is

Fatal: Need a single revision

Unable to find current origin/ revision in submodule path

I also tried

 git submodule foreach git pull

so that it will pull the commit id, but it simply returns with

Entering name_of_the_submodule

Already up to date.

Can anyone please help me?

P.S: I have already gone through many tutorials and question and answers. So if you want to downvote this for fun, then please first point to an answer and I will delete this post.

Upvotes: 5

Views: 7103

Answers (2)

infoclogged
infoclogged

Reputation: 3997

I am answering my own question, after a little bit of research, that might be helpful to the others:

It is a big pain to understand git submodules, but once you get it, everything starts making sense !

The following post shows:

  • adding submodules and letting others sync with your submodules.
  • updating submodules and letting others sync with your submodules.
  • removing submodules and letting other sync with your submodules.
  • updating the removed submodules.

Adding submodules

git submodule add -b

The entry in .gitmodules ( name, path, url, branch ) downloads the respective submodule by

git submodule update --init

This does three important thing, the first two of which are hidden from the user:

  1. updates .git/config with an extra entry ( submodules )

  2. downloads a repository in bare form under .git/modules. That means, there is .git inside a .git.

  3. checks out the git submodule from the .git/modules into the parent directory.

Now, on Day 2, the commiter, who commited the submodule realises, that he should change the submodule to some other commit and not the HEAD. So, he would go to his local repository and then go the submodule path and then checkout the commit that he wants by simply invoking

git checkout <hash>
cd <parent dir>
git submodule status

At this point, the git submodule status still does not shows the new hash. The new hash will only be visible when the changes are staged. Now, the commiter, just needs to stage ( add ), commit and push the changes, so that it is visible to all the other developers.

Updating the added submodule

On Day 3, the other developers, would update their repository by just invoking the command

git pull # this is to get the latest commit of the parent git repository.
git submodule update --force # update the submodule with latest hash

Basically, here the point is simple: The submodule does not react until and unless it is told to do so. Just doing git pull, wont update the git submodule. The developers can continue to work on their local submodules and not sync them to the one on the server "forever". The submodule update would happen on explicitly invoking the git submodule update command.

Removing submodule

Now, on Day4, the committer, decides to remove the git submodule completely. Here the steps are also not simple, because there is nothing called git submodule rm that should have been equivalent to git submodule add. This can be done only and only if the following sequence is followed:

git submodule deinit submodulename
  1. this deletes the .git/config entry.

  2. this clears the submodule directory !! You will see nothing in the submdoule directory after this command.

  3. But the contents of the submodule are still available under .git/modules

Hence a git status -u here will still show that Everyting is upto date !

So show the removals,

git rm submodulepath

At this point git status will return that .gitmodules has been changed ( the submodule has been deleted ) and the submodule path has been deleted. Commit and push the changes.

Updating with removed submodule

On Day5, the developers want to delete the submodules "automatically" like it did with git submodule update. So they do first a git pull, which succesfully removes all indices to the git submodules

 git submodule status # shows nothing

BUT, the .git/config still contains valid submodule entry and the submodule folder is there with all its contents and the bare repository under .git/submodules ! There is no command to delete them. All of them must be explicitly removed via hand..( Please correct me if I am wrong )

Upvotes: 3

Thibault D.
Thibault D.

Reputation: 10105

After you have cloned the submodule as described in your question:

git submodule add -b master url localpath

Then you should be able to changedir to the submodule:

cd localpath

Once in the submodule, you can use any git commands and they will only affect the submodule's repo. For example, you can checkout that holy branch or revision:

git checkout <branch|tag|hash>

or checkout the second-to-last revision in master branch:

git checkout HEAD~1

Then changedir back to the main git repo:

cd ..

And git status should yield something like:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitmodules
    new file:   localpath

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

Then just add the changes done to your submodule:

git add localpath

And commit

git commit -m "Add submodule url to localpath with older working commit"

Upvotes: 2

Related Questions