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

Re: Change set based shallow clone

From
Llinux@horizon.com <linux@horizon.com>
Date
Sep 8, 2006, 01:01 UTC
Message-ID
<20060908010112.6962.qmail@science.horizon.com>
In-Reply-To
<9e4733910609071252ree73effwb06358e9a22ba965@mail.gmail.com>
> Here's a change set based shallow clone scheme I've been thinking
> about, does it have potential?
Well, let's look at the problems...

You might want to look at the explanation of the current git network protocol at http://www.spinics.net/lists/git/msg08899.html

I'm just understanding it myself, but as best I understant it, it has four phases:

- First, the server lists all of the heads it has, by SHA1 and name.
- Second, the client tells it which ones it wants, by name.
- Third, an interactive protocol is entered in which the client
  tells the server which commits it has in terms the server can
  understand.  This proceeds as follows:
  - For each head the client has, it lists commit objects going
    backwards in history.
  - As soon as the server sees one that it has heard of, it sends
    back "ACK <hash> continue".  The client stops tracing that
    branch and starts in on the next one.
  - (Periodically, the client sends a ping to the server, which
    responds "NAK" if it's still alive.)
  - This continues until the client says "done".

At this point, the server knows a set of commits which the client has, and a set of commits which the client wants. Then it invokes

	git-rev-list --objects-edge <want1> <want2> ^<have1> ^<have2>

(In practice, there will be a lot more than two of each, but forgive me if I simplify.)

This builds a list of commits that are ancestors of <want1> and <want2> but not <have1> or <have2>. (A commit is considered an ancestor of itself, so <want1> and <want2> are in the set, while <have1> and <have2> are not.)

Then it enumerates the complete trees of each of those commits. Then it subtracts from that object set all of the trees and blobs in the <have1> and <have2> commits.

This is a good approximation to the set of objects that the client needs to be sent. It does not search the ancestors of <have1> and <have2>, so it is possible that a copy of some object exists in an older commit, and the state in <want1> is a reversion to a pre-<have1> state, but it's unlikely and not worth looking for. Sending it redundantly is harmless.

Then, this set of objects is piped to git-pack-objects, which finds them and builds a pack file. If the objects are stored locally as deltas relative to other objects which are either to be sent, or are in the <have1> or <have2> commits (which information is included in the data output by git-rev-list), the delta is copied to the pack file verbatim. Otherwise, more CPU is spent to pack it.

Again, the server is allowed to check for deltas against ancestors of <have1> or <have2>, but doesn't bother for efficiency.

Fourth, the pack file is sent to the client, which unpacks it (and discards any duplicates).

> When the client wants a shallow clone it starts by telling the server
> all of the HEADs and how many change sets down each of those HEADs it
> has locally. That's a small amout of data to transmit and it can be
> easily tracked. Let's ignore merged branches for the moment.
When you say "change set", I'm going to assume you mean "commit object".

Okay. Now, the server hasn't heard of one or more of those commit objects, because they're local changes. What then?

Another issue is that a client with a nearly-full copy has to do a full walk of its history to determine the depth count that it has. That can be more than 2500 commits down in the git repository, and worse in the mozilla one. It's actually pretty quick (git-show-branch --more=99999 will do it), but git normally tries to avoid full traversals like the plague

Oh, and was "for the moment" supposed to last past the end of your e-mail? I don't see what to do if there's a merge in the history and the depth on different sides is not equal. E.g. the history looks like:

...a---b---c---d---e---f
                  /     \
      ...w---x---y       HEAD
                        /
        ...p---q---r---s
Where "..." means that there are ancestors, but they're missing.
Show 8 quoted lines
> If you haven't updated for six months when the server walks backwards
> for 10 change sets it's not going to find anything you have locally.
> When this situation is encountered the server needs to generate a
> delta just for you between one of the change sets it knows you have
> and one of the 10 change sets you want. By generating this one-off
> delta it lets you avoid the need to fetch all of the objects back to a
> common branch ancestor. The delta functions as a jump over the
> intervening space.

Your choice of words keeps giving me the impression that you believe that a "change set" is a monolithic object that includes all the changes made to all the files. It's neither monolithic nor composed of changes. A commit objects consists soley of metadata, and contains a pointer to a tree object, which points recursively to the entire project state at the time of the commit.

There is massive sharing of component objects between successive commits, but they are NOT stored as deltas relative to one another.

The pack-forming heuristics tend to achieve that effect, but it is not guaranteed or required by design.

Please understand that, deep in your bones: git is based on snapshots, not deltas.

But okay, so we've sent the client the latest 10 commits, with a dangling tail at the bottom. (The files may have been sent as deltas against the old state, or just fresh compressed copies, but that doesn't matter.) Then the heads like "origin" have been advanced.

So the old commit history is now unreferenced garbage; nothing points to it, and it will be deleted next time git-prune is run. Is that the intended behavior? Or should updates to an existing clone always complete the connections?

Previous: Aneesh Kumar K.VNext: Jon Smirl
Message 23 of 99 in “Change set based shallow clone”
  1. Jon SmirlSep 7, 2006
  2. Jakub NarebskiSep 7, 2006
  3. Jon SmirlSep 7, 2006
  4. Jeff KingSep 7, 2006
  5. Jakub NarebskiSep 7, 2006
  6. Jakub NarebskiSep 7, 2006
  7. Junio C HamanoSep 7, 2006
  8. Jon SmirlSep 7, 2006
  9. Anand KumriaSep 10, 2006
  10. Andreas EricssonSep 8, 2006
  11. Junio C HamanoSep 7, 2006
  12. Jakub NarebskiSep 7, 2006
  13. Martin LanghoffSep 8, 2006
  14. Junio C HamanoSep 8, 2006
  15. Martin LanghoffSep 8, 2006
  16. Junio C HamanoSep 8, 2006
  17. A Large Angry SCMSep 8, 2006
  18. Jon SmirlSep 8, 2006
  19. Jakub NarebskiSep 8, 2006
  20. Petr BaudisSep 9, 2006
  21. Jakub NarebskiSep 9, 2006
  22. Aneesh Kumar K.VSep 8, 2006
  23. linux@horizon.comSep 8, 2006
  24. Jon SmirlSep 8, 2006
  25. Jakub NarebskiSep 8, 2006
  26. Junio C HamanoSep 8, 2006
  27. linux@horizon.comSep 8, 2006
  28. Jon SmirlSep 8, 2006
  29. Jakub NarebskiSep 8, 2006
  30. Linus TorvaldsSep 8, 2006
  31. Jon SmirlSep 8, 2006
  32. Paul MackerrasSep 8, 2006
  33. Jon SmirlSep 9, 2006
  34. Paul MackerrasSep 10, 2006
  35. Jon SmirlSep 10, 2006
  36. linux@horizon.comSep 10, 2006
  37. Jon SmirlSep 10, 2006
  38. linux@horizon.comSep 10, 2006
  39. Linus TorvaldsSep 10, 2006
  40. Jon SmirlSep 10, 2006
  41. Linus TorvaldsSep 11, 2006
  42. Paul MackerrasSep 10, 2006
  43. Linus TorvaldsSep 11, 2006
  44. Linus TorvaldsSep 11, 2006
  45. Junio C HamanoSep 11, 2006
  46. Junio C HamanoSep 11, 2006
  47. Paul MackerrasSep 11, 2006
  48. linux@horizon.comSep 11, 2006
  49. Jon SmirlSep 11, 2006
  50. Junio C HamanoSep 11, 2006
  51. Paul MackerrasSep 11, 2006
  52. Junio C HamanoSep 11, 2006
  53. Jakub NarebskiSep 12, 2006
  54. Junio C HamanoSep 12, 2006
  55. Jakub NarebskiSep 12, 2006
  56. Jakub NarebskiSep 11, 2006
  57. Junio C HamanoSep 10, 2006
  58. Shawn PearceSep 11, 2006
  59. Junio C HamanoSep 11, 2006
  60. Shawn PearceSep 11, 2006
  61. Junio C HamanoSep 11, 2006
  62. Jakub NarebskiSep 11, 2006
  63. Shawn PearceSep 11, 2006
  64. Junio C HamanoSep 11, 2006
  65. Shawn PearceSep 11, 2006
  66. Junio C HamanoSep 11, 2006
  67. Shawn PearceSep 11, 2006
  68. Jon SmirlSep 11, 2006
  69. Paul MackerrasSep 9, 2006
  70. Linus TorvaldsSep 9, 2006
  71. Junio C HamanoSep 9, 2006
  72. Paul MackerrasSep 9, 2006
  73. Linus TorvaldsSep 9, 2006
  74. Marco CostalbaSep 9, 2006
  75. Linus TorvaldsSep 9, 2006
  76. Marco CostalbaSep 9, 2006
  77. linux@horizon.comSep 9, 2006
  78. Marco CostalbaSep 9, 2006
  79. Linus TorvaldsSep 9, 2006
  80. Jeff KingSep 9, 2006
  81. Junio C HamanoSep 9, 2006
  82. Jeff KingSep 9, 2006
  83. Linus TorvaldsSep 9, 2006
  84. Jon SmirlSep 9, 2006
  85. Linus TorvaldsSep 10, 2006
  86. Junio C HamanoSep 10, 2006
  87. Marco CostalbaSep 10, 2006
  88. Junio C HamanoSep 10, 2006
  89. Marco CostalbaSep 10, 2006
  90. Marco CostalbaSep 10, 2006
  91. Junio C HamanoSep 10, 2006
  92. Marco CostalbaSep 10, 2006
  93. Junio C HamanoSep 10, 2006
  94. linux@horizon.comSep 10, 2006
  95. Marco CostalbaSep 10, 2006
  96. Paul MackerrasSep 11, 2006
  97. linux@horizon.comSep 11, 2006
  98. Jakub NarebskiSep 10, 2006
  99. Josef WeidendorferSep 10, 2006

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.