How can I get a git submodule's associated commit ID from a past commit in the parent clone?
Asked Answered
T

5

47

Is there a way, short of actually checking out the parent commit, to determine a submodule's SHA-1 commit ID based on a commit ID in the parent clone? I know I can find the currently associated SHA-1 with git submodule.

Here's an example:

  • I have a clone with a single submodule foo that has changed several times in the last month.
  • I have a tag in the parent clone that is a few weeks old called released-1.2.3. I want to find out what the associated SHA-1 of foo was for this tagged commit.
  • I could simply check out released-1.2.3 and use git submodule to see, but I'm wondering if there's a way to do this without affecting the working tree, as I want to script it.

I want to do this because I want to construct a script to do a 'diff' on all changes within a submodule between two commits within the parent repository - i.e. "tell me what files changed within the submodule foo between these two commits in the parent."

Thanks answered 21/10, 2010 at 2:18 Comment(0)
E
58

You may use git-ls-tree to see what the SHA-1 id of a given path was during a given commit:

$ git ls-tree released-1.2.3 foo
160000 commit c0f065504bb0e8cfa2b107e975bb9dc5a34b0398  foo

(My first thought was git show released-1.2.3 foo, but that fails with "fatal: bad object".)

Since you are scripting the output, you will probably want to get just the SHA-1 id by itself, e.g.:

$ git ls-tree released-1.2.3 foo | awk '{print $3}'
c0f065504bb0e8cfa2b107e975bb9dc5a34b0398

Also: When writing scripts around git, try to stick to the plumbing commands, as described in the manual. They have a more stable interface, while the more familiar “porcelain” commands will possibly change in incompatible ways.

Emelinaemeline answered 24/10, 2010 at 20:3 Comment(5)
I think this is the answer I'm looking for - this does seem to return the hash of the submodule for the specified parent commit. Thank you. Also, plumbing comment noted - thanks.Thanks
To discover submodules with their hashes at arbitrary commit: git ls-tree --full-tree -r commit|grep ^160000. The grep is for the mode used for submodule links.Nonjuror
@S.ChristofferEliesen, add -r to find all submodules, not only those in ./Lessen
@JoshLee Care to explain what you mean when you say that scripting with git should generally be restricted to plumbing commands? Clearly, these are a subset of everything one can tell git to do, but why are they preferable for this purpose?Lilongwe
I don't understand, what is foo ? What is released-1.2.3 ?Armilla
D
7

This one worked for me:

$ git rev-parse released-1.2.3^{commit}:foo
<SHA1>

Perhaps also quite easy to use in script.

Dribble answered 29/6, 2015 at 12:27 Comment(2)
I was surprised to see that rev-parse understood the submodule.Resinoid
I think you don't need to explicitly deref the reference with ^{commit}, just use plain <commit-ish>:<submodule-path>. Other than that that's a great answerAbsorbance
T
2

I did find one promising avenue:

$ git log --raw <since>..<until> --submodule -- <path/to/submodule>

With the --raw option, this does print out the (abbreviated) SHA-1 IDs corresponding to the submodule's associated commits. Unfortunately the output is very verbose and will take some work to process in a script.

What I really need is a git facility that, given a parent commit ID, gives me the latest change to a submodule prior to that commit. I.e. which submodule SHA-1 'git submodule update' would check out if I were to actually checkout that parent commit.

Thanks answered 21/10, 2010 at 2:41 Comment(2)
git log --format=%H will get you hashes.. so will git rev-parseAlben
Thanks for your comments, adymitruk. However --format=%H and rev-parse return the hashes for the parent clone's commit, not the actual hash of the submodule, unfortunately.Thanks
A
0

git slave (gits) might be your answer.

http://gitslave.sourceforge.net/

But you can also do this with plain git.. it's not as easy.

Alben answered 21/10, 2010 at 2:41 Comment(0)
G
0

git ls-tree will do the job. But sometimes you should call it several times or use -r to show subentries recursively.

    ├─project
    │  └─submodules
    │      ├─submodule_a
    │      ├─submodule_b
    │      ├─...

For example, if you has such a project directory, and you want the commit id of submodule_a with an tag name in parent module.

git ls-tree v5.4.0

will give you the tree id of directory submodules, not commit id. It looks like as following.

040000 tree e542bc1b084a0394ff16452c27df6572366e0009    submodules

Just feed ls-tree with the tree id, and you will get the actual commit id of each submodule.

git ls-tree e542bc

You will get something like this.

160000 commit 0f253bf94e0345600cb7a234a24eeec8ee3533bd  submodule_a
160000 commit 0edcbaf94e034987cb4eeec8ee3533bd12349ade  submodule_b

Or just use

git ls-tree v5.4.0 -r

to check all entries tree id or commit id.

Greece answered 9/5, 2019 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.