threads / discuss / 48066

get commit ID from a tree object ID

Subject: get commit ID from a tree object ID

## tl;dr

6 messages between Mar 17, 2018 and Mar 26, 2018.

replies: 5people: 6as markdown or json

Michal Novotny· Mar 17, 2018, 12:17 UTC · lore
Hello,
let's say I have made an annotated tag on a certain treeish:
$ git tag -a -m msg tagname HEAD:
Now, I can try to see the content of the tag:

$ git tag -v tagname object 42a1c36553a50ceae2f75ffc4b1446c6c393eae7 type tree tag tagname tagger clime <clime@redhat.com> 1521288727 +0100

msg error: no signature found

Can I use that object ID 42a1c36553a50ceae2f75ffc4b1446c6c393eae7 to get back to a particular commit from which the tag was created? The reason is that I would eventually like to checkout that commit.

Thank you clime

Konstantin Khomoutov· Mar 17, 2018, 13:01 UTC · re: Michal Novotny · lore

Re: get commit ID from a tree object ID

On Sat, Mar 17, 2018 at 01:17:12PM +0100, Michal Novotny wrote:
Show 19 quoted lines
> let's say I have made an annotated tag on a certain treeish:
> 
> $ git tag -a -m msg tagname HEAD:
> 
> Now, I can try to see the content of the tag:
> 
> $ git tag -v tagname
> object 42a1c36553a50ceae2f75ffc4b1446c6c393eae7
> type tree
> tag tagname
> tagger clime <clime@redhat.com> 1521288727 +0100
> 
> msg
> error: no signature found
> 
> 
> Can I use that object ID 42a1c36553a50ceae2f75ffc4b1446c6c393eae7 to
> get back to a particular commit from which the tag was created? The
> reason is that I would eventually like to checkout that commit.

In general, you can't, and that's because there can be any number of commits referencing that tree. A typical case is a tree object representing a subdirectory of your project which changes rarily, if ever - in this case, each commit which includes the same state of this subdirectory will refer the same tree object.

Another point to consider is that the commit itself only refers to a single tree object -- that one which records the state of the top-level project directory, and it usually refers to other three objects which may, in turn, refer to others and so on - all the way down.

So actually a generic approach to what you need is a full scan of all the commits in the repository with recursive traversing of the hierarchy of trees of each of them (via `git ls-tree`) and looking for the SHA-1 name of the reference tree object. As you can see, this is not going to be fast on repos of realistic size.

Jeff King· Mar 17, 2018, 16:18 UTC · re: Konstantin Khomoutov · lore

Re: get commit ID from a tree object ID

On Sat, Mar 17, 2018 at 04:01:28PM +0300, Konstantin Khomoutov wrote:
Show 5 quoted lines
> So actually a generic approach to what you need is a full scan of all
> the commits in the repository with recursive traversing of the hierarchy
> of trees of each of them (via `git ls-tree`) and looking for the SHA-1
> name of the reference tree object.  As you can see, this is not going to
> be fast on repos of realistic size.

If you assume that the tree is a root tree (which is by no means certain, but a good guess), it's not _too_ bad to do:

  git rev-list --all --format='%T %H' | grep ^$desired_tree

That's linear in the number of commits, but still takes only about 7 seconds on linux.git.

If you want to dig further, you can use the diff machinery to show which commit introduced a particular tree, like:

  git rev-list --all |
  git diff-tree --stdin --pretty=raw --raw -t -r |
  less +/$desired_tree

That "less" will find the mentioned tree, and then you'll have to manually read the commit. It would be possible to do it mechanically with a short perl script, but I'll leave that as an exercise for the reader.

-Peff
Junio C Hamano· Mar 17, 2018, 17:57 UTC · re: Jeff King · lore

Re: get commit ID from a tree object ID

Jeff King <peff@peff.net> writes:
Show 11 quoted lines
> If you want to dig further, you can use the diff machinery to show which
> commit introduced a particular tree, like:
>
>   git rev-list --all |
>   git diff-tree --stdin --pretty=raw --raw -t -r |
>   less +/$desired_tree
>
> That "less" will find the mentioned tree, and then you'll have to
> manually read the commit. It would be possible to do it mechanically
> with a short perl script, but I'll leave that as an exercise for the
> reader.

Before Stefan jumps in ;-) I wonder if a recently materialized "find-object" option to the diff family can be used here as a sugar-coated way.

Stefan Beller· Mar 26, 2018, 22:14 UTC · re: Junio C Hamano · lore

Re: get commit ID from a tree object ID

On Sat, Mar 17, 2018 at 10:57 AM Junio C Hamano <gitster@pobox.com> wrote:
> Jeff King <peff@peff.net> writes:
Show 11 quoted lines
> > If you want to dig further, you can use the diff machinery to show which
> > commit introduced a particular tree, like:
> >
> >   git rev-list --all |
> >   git diff-tree --stdin --pretty=raw --raw -t -r |
> >   less +/$desired_tree
> >
> > That "less" will find the mentioned tree, and then you'll have to
> > manually read the commit. It would be possible to do it mechanically
> > with a short perl script, but I'll leave that as an exercise for the
> > reader.
> Before Stefan jumps in ;-) I wonder if a recently materialized
> "find-object" option to the diff family can be used here as a
> sugar-coated way.

I am late to jump in, but testing the 'git log --find-object' seems to have issues with trees named by sha1 here, but the named tree via <commit>:<path> still seems to work.

It seems reasonable to be able to find trees using the find-object flag, though.

Stefan
Jonathan Nieder· Mar 26, 2018, 22:21 UTC · re: Stefan Beller · lore

Re: get commit ID from a tree object ID

Hi,
Stefan Beller wrote:
> On Sat, Mar 17, 2018 at 10:57 AM Junio C Hamano <gitster@pobox.com> wrote:
>> Jeff King <peff@peff.net> writes:
Show 19 quoted lines
>>> If you want to dig further, you can use the diff machinery to show which
>>> commit introduced a particular tree, like:
>>>
>>>   git rev-list --all |
>>>   git diff-tree --stdin --pretty=raw --raw -t -r |
>>>   less +/$desired_tree
>>>
>>> That "less" will find the mentioned tree, and then you'll have to
>>> manually read the commit. It would be possible to do it mechanically
>>> with a short perl script, but I'll leave that as an exercise for the
>>> reader.
>
>> Before Stefan jumps in ;-) I wonder if a recently materialized
>> "find-object" option to the diff family can be used here as a
>> sugar-coated way.
>
> I am late to jump in, but testing the 'git log --find-object'
> seems to have issues with trees named by sha1 here,
> but the named tree via <commit>:<path> still seems to work.

Experimenting a little more, I wondered if "-t" wasn't being passed by default:

  $ git --oneline log -t --find-object=$(git rev-parse HEAD~30:Documentation/technical)
  $
No, that's not it.  Could it have to do with merges?
  $ git log --oneline -m --first-parent --find-object=$(git rev-parse HEAD~30:Documentation/technical)
  df6cfe8c30 Merge branch 'debian-experimental' into google3
  f86d5fd2e4 Merge branch 'debian-experimental' into google3
Yes.
That doesn't explain why <commit>:<path> worked for you, though. :)

Thanks, Jonathan

← back to recent threads