git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: More precise tag following

From
Shawn O. Pearce <spearce@spearce.org>
Date
Jan 27, 2007, 08:01 UTC
Message-ID
<20070127080126.GC9966@spearce.org>
In-Reply-To
<7vy7nqxd08.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> wrote:
> What if (I know, this discussion does not belong here until
> 1.5.0 final) we had a "reverse" database that keeps track of
> what tag references which object, and "git rev-list" knows how
> to exploit it?

It'd be useful. In as many ways as you suggest. But it also would be downright difficult to transfer between repositories, as you have already pointed out in a public forum to yourself. :-)

Show 12 quoted lines
>  - If a single-path following turns out to be too expensive
>    (there was a longstanding talk about "git log --single-follow
>    $path"; "git blame" also follows a single path although the
>    target it follows can fork into two or more when following
>    cut&pastes) because we need to explode multi-level trees for
>    each commit while traversing commit ancestry, we could define
>    an annotation to a commit that lists the set of paths the
>    commit touches relative to each of its parents (so the object
>    contains N lists of paths), so that pathspec limiting needs
>    to open and read only one object to figure out that the trees
>    do not have to be opened to skip the commit and/or a merge
>    can be simplified.

_THIS_ is worth doing. I've been having a lot of discussion on #git with Simon 'corecode' Schubert and Chris Lee about how poorly git-blame performs compared to its counterpart in Subversion.

Basically Subversion is storing file-level revision ancestry data within its commit data, allowing it to quickly skip back through the commits which modified that file.

Git doesn't have this information and must instead traverse the entire DAG, at least until the file was initially added to the tree. With 440,000+ revisions and a file which exists in nearly all of them, getting anything from "git-blame" or "git-log -- foo.c" takes ages.

Based on some (limited) profiling with Shark it seems we spend about 50% of our CPU time doing zlib decompression of objects and almost another 14% parsing the tree objects to apply the path limiter. The only way to speed up blame/log operations is to reduce the number of decompressions we need to do to the bare minium, and maybe also reduce the tree parsing overheads. Do that and we can maybe drop the running time to 1/4th the current time.

One idea Simon and I were talking about was to store a reverse file/tree-level DAG in the header of each tree/blob object in the pack file. This additional header would be something like a list of triplets:

  (descendant-commit, ancestor-commit, ancestor-object)
where:
  descendant-commit: the "current" commit being looked at.
  ancestor-commit:   the commit which descendant-commit
                     derives from (directly or indirectly)
  ancestor-object:   prior version (descendant-commit^:path)

This triplet would probably be encoded with descendant-commit using OBJ_REF, ancestor-commit being an OBJ_OFS style back reference within the pack (or OBJ_REF if not in this pack) and ancestor-object would also be an OBJ_REF. So a triplet probably would wind up costing ~60 bytes.

Triplets would only be stored if ancestor-object != this-object, so basically only for the commits which changed the path the tree/blob is occupying in descendant-commit.

Finding the prior revision of a tree or file would be a matter of finding the triplet which matches the current commit, then jumping through to the ancestor-* values. If no triplet matches the current commit then we peel back the parents of the current commit and try again with those. Worst case we do what we do now, which is walk the DAG. ;-)

This of course penalizes objects which don't ever change, as we'd have to walk back a good chunk of the DAG before we find a matching triplet. But I would suspect that files which never change are also not given to log/blame very often either. And once we do find a triplet, we can skip through the DAG in time proportional to the rate of change for the path, rather than to the entire repository.

Thoughts?
-- 
Shawn.
Previous: Junio C HamanoNext: Junio C Hamano
Message 3 of 92 in “More precise tag following”
  1. Junio C HamanoJan 26, 2007
  2. Junio C HamanoJan 26, 2007
  3. Shawn O. PearceJan 27, 2007
  4. Junio C HamanoJan 27, 2007
  5. Jeff KingJan 27, 2007
  6. Nicolas PitreJan 27, 2007
  7. Simon 'corecode' SchubertJan 27, 2007
  8. Johannes SchindelinJan 27, 2007
  9. Simon 'corecode' SchubertJan 27, 2007
  10. Jakub NarebskiJan 27, 2007
  11. Linus TorvaldsJan 27, 2007
  12. Johannes SchindelinJan 27, 2007
  13. Simon 'corecode' SchubertJan 27, 2007
  14. Johannes SchindelinJan 27, 2007
  15. Simon 'corecode' SchubertJan 27, 2007
  16. Nicolas PitreJan 27, 2007
  17. Linus TorvaldsJan 27, 2007
  18. Linus TorvaldsJan 27, 2007
  19. Junio C HamanoJan 27, 2007
  20. Linus TorvaldsJan 27, 2007
  21. Junio C HamanoJan 28, 2007
  22. git-blame --porcelain: quote filename in c-style when needed.Junio C Hamano, Jan 28, 2007
  23. git-blame --incremental: don't use pagerRené Scharfe, Jan 28, 2007
  24. Junio C HamanoJan 28, 2007
  25. Junio C HamanoJan 28, 2007
  26. René ScharfeJan 29, 2007
  27. git blame --progressJunio C Hamano, Jan 29, 2007
  28. Simon 'corecode' SchubertJan 29, 2007
  29. Alex RiesenJan 29, 2007
  30. Matthias LederhoferJan 29, 2007
  31. Junio C HamanoJan 29, 2007
  32. René ScharfeJan 29, 2007
  33. Linus TorvaldsJan 29, 2007
  34. Junio C HamanoJan 30, 2007
  35. Linus TorvaldsJan 28, 2007
  36. Junio C HamanoJan 28, 2007
  37. Linus TorvaldsJan 28, 2007
  38. Junio C HamanoJan 28, 2007
  39. document 'blame --incremental'Junio C Hamano, Jan 28, 2007
  40. Junio C HamanoJan 28, 2007
  41. Jeff KingJan 28, 2007
  42. Junio C HamanoJan 30, 2007
  43. Shawn O. PearceJan 30, 2007
  44. Linus TorvaldsJan 30, 2007
  45. Junio C HamanoJan 28, 2007
  46. Shawn O. PearceJan 29, 2007
  47. Junio C HamanoJan 29, 2007
  48. Shawn O. PearceJan 29, 2007
  49. Linus TorvaldsJan 29, 2007
  50. Simon 'corecode' SchubertJan 29, 2007
  51. Theodore TsoJan 29, 2007
  52. Linus TorvaldsJan 29, 2007
  53. Jakub NarebskiJan 29, 2007
  54. Shawn O. PearceJan 29, 2007
  55. Jakub NarebskiJan 29, 2007
  56. Shawn O. PearceFeb 9, 2007
  57. David KågedalJan 31, 2007
  58. David KågedalJan 31, 2007
  59. Peter EriksenJan 31, 2007
  60. David KågedalJan 31, 2007
  61. Peter EriksenJan 31, 2007
  62. Jakub NarebskiJan 31, 2007
  63. David KågedalJan 31, 2007
  64. Simon 'corecode' SchubertJan 27, 2007
  65. Johannes SchindelinJan 27, 2007
  66. Simon 'corecode' SchubertJan 27, 2007
  67. Johannes SchindelinJan 27, 2007
  68. Jakub NarebskiJan 27, 2007
  69. Linus TorvaldsJan 27, 2007
  70. Linus TorvaldsJan 27, 2007
  71. Jakub NarebskiJan 27, 2007
  72. Linus TorvaldsJan 27, 2007
  73. Chris LeeJan 27, 2007
  74. Theodore TsoJan 28, 2007
  75. Linus TorvaldsJan 28, 2007
  76. David LangJan 28, 2007
  77. Nicolas PitreJan 29, 2007
  78. Linus TorvaldsJan 29, 2007
  79. Nicolas PitreJan 29, 2007
  80. Chris LeeJan 29, 2007
  81. Eric WongJan 29, 2007
  82. Eric WongJan 30, 2007
  83. Eric WongJan 30, 2007
  84. Eric WongJan 30, 2007
  85. Jakub NarebskiJan 27, 2007
  86. Jeff KingJan 27, 2007
  87. Linus TorvaldsJan 27, 2007
  88. Jeff KingJan 27, 2007
  89. Theodore TsoJan 28, 2007
  90. Randal L. SchwartzJan 28, 2007
  91. Jeff KingJan 28, 2007
  92. Shawn O. PearceJan 28, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.