Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check out a git commit including submodules as they were at that time

How do we check out a git commit including submodules as they were at that time?

One reason why we might want this is to look at a previous version of the main program for which we need to rebuild it with the submodules in the version that was used at the time of the commit.

Given this, we could even use this in regular workflow:

  • First update all submodules with git submodule update --remote --merge, then try to build to see if the program can work with the newest version of all submodules.
  • If it works we are done. If it does not work, then we could go to the previous version of the program incl. the submodule-versions it used and with which it works.
  • Then update the submodules one-by-one and change the program to work with them.

We can kind-of do it by manually looking at each submodule: which commit had the appropriate timestamp (and hope that the program used the then-most-uptodate version). It would be much better if we could see commit X of the program used submodule commit Y. And check those out for each submodule.

like image 658
Bernd Elkemann Avatar asked Jan 29 '17 10:01

Bernd Elkemann


People also ask

Does git pull include submodules?

Pulling with submodules. Once you have set up the submodules you can update the repository with fetch/pull like you would normally do. To pull everything including the submodules, use the --recurse-submodules and the --remote parameter in the git pull command .

What does checking out a commit do?

When it points to a branch, Git doesn't complain, but when you check out a commit, it switches into a “detached HEAD” state. The point is, your development should always take place on a branch—never on a detached HEAD . This makes sure you always have a reference to your new commits.

What are submodules in git?

A git submodule is a record within a host git repository that points to a specific commit in another external repository. Submodules are very static and only track specific commits. Submodules do not track git refs or branches and are not automatically updated when the host repository is updated.

What does git pull -- recurse submodules do?

git submodule foreach git pull origin master or git pull origin master --recurse-submodules is what you want if you intend to update each submodule to the latest from their origin repositories. Only then will you get pending changes in the parent repo with updated revision hashes for submodules.

What is the use of--Recurse-submodules in Git checkout?

Using the --recurse-submodules flag of git checkout can also be useful when you work on several branches in the superproject, each having your submodule pointing at different commits.

How do I see changes in a submodule in Git?

By default, the git pull command recursively fetches submodules changes, as we can see in the output of the first command above. However, it does not update the submodules. This is shown by the output of the git status command, which shows the submodule is “modified”, and has “new commits”.

Why does git pull--recurse-submodules fail when using SuperProject?

In that case, it is possible for git pull --recurse-submodules, or git submodule update, to fail if the superproject references a submodule commit that is not found in the submodule remote locally configured in your repository. In order to remedy this situation, the git submodule sync command is required:

How do I Checkout a specific commit in Git?

Step 1: Clone the repository or fetch all the latest changes and commits. Step 2: Get the commit ID (SHA) that you want to checkout. From your local repository, you can get the commit SHA from... Step 3: Copy the commit (SHA) id and checkout using the following command. git checkout... Step 4: If ...


1 Answers

In this case, you just need to run git submodule update --checkout (no --merge, no --remote) after checking out a previous commit.

There is a lot of confusion around submodules. The basics are actually fairly simple though:

  • Each submodule is its own Git repository.
  • From the submodule, one refers to the "containing" Git as a superproject.
  • The superproject records the URL and path—these being things you would normally control or provide by running git clone—for each of its submodules in the .gitmodules file.
  • Meanwhile, when you make a commit in the superproject, this commit contains, in its snapshot, all the normal trees and files as usual, but also, for each submodule, the commit ID to check out when checking out the submodule.1

This has the effect of "freezing" the appropriate submodule commit into each superproject commit. It is—or was originally—intended to manage third party code, where the submodule itself changes rarely compared to the superproject.

This model is not at all flexible, and is not suitable for the way many people want to use submodules, which is to keep them at the tip of some branch. So submodules grew the ability to update to branch names, or to be worked-in and have the work rebased and/or merged. These new abilities spawned the submodule.name.update configuration entries and git submodule update --remote options.

If you have not configured any of these items, git submodule update alone will check out the desired (recorded) submodule commits for each submodule recorded in the current, i.e., HEAD, commit of the superproject. If you have configured some of these, you can use git submodule update --checkout to override the configuration and cause a git checkout hash-id in each submodule. Note that adding --force makes Git do this submodule checkout even if the HEAD is already at that entry. But since each submodule is its own Git repository, the submodule's checkout has its own interaction with its own (per-repository / per-work-tree) index and work-tree.2

Again, every submodule is its own Git repository, which means a submodule of the current superproject may have submodules of its own. If so, this makes the submodule a superproject as well, and this is where the --recursive flag comes in. If you are not nesting submodules, none of this complexity will affect you.


1In other words, the index for the superproject has an entry for each submodule. The type of this index entry is "gitlink", which stores the SHA-1 read from HEAD in the submodule. These gitlink entries are treated as sort of a weird cross between a symlink and a directory.

2In other words, if you have manually entered one of the submodules and modified the index and/or work-tree, the git checkout run inside that submodule, if any, may still carry your modifications into the new checked-out commit.

like image 141
torek Avatar answered Oct 25 '22 13:10

torek