doc: describe Git bundle format
diff mbox series

Message ID 20200130225818.193825-1-masayasuzuki@google.com
State New
Headers show
Series
  • doc: describe Git bundle format
Related show

Commit Message

Masaya Suzuki Jan. 30, 2020, 10:58 p.m. UTC
The bundle format was not documented. Describe the format with ABNF and
explain the meaning of each part.

Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
---
 Documentation/technical/bundle-format.txt | 40 +++++++++++++++++++++++
 1 file changed, 40 insertions(+)
 create mode 100644 Documentation/technical/bundle-format.txt

Comments

Johannes Schindelin Jan. 31, 2020, 1:56 p.m. UTC | #1
Hi,

On Thu, 30 Jan 2020, Masaya Suzuki wrote:

> The bundle format was not documented. Describe the format with ABNF and
> explain the meaning of each part.

LGTM,
Dscho

>
> Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
> ---
>  Documentation/technical/bundle-format.txt | 40 +++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
>  create mode 100644 Documentation/technical/bundle-format.txt
>
> diff --git a/Documentation/technical/bundle-format.txt b/Documentation/technical/bundle-format.txt
> new file mode 100644
> index 0000000000..dbb80225b5
> --- /dev/null
> +++ b/Documentation/technical/bundle-format.txt
> @@ -0,0 +1,40 @@
> += Git bundle v2 format
> +
> +The Git bundle format is a format that represents both refs and Git objects.
> +
> +== Format
> +
> +We will use ABNF notation to define the Git bundle format. See
> +protocol-common.txt for the details.
> +
> +----
> +bundle    = signature references pack
> +signature = "# v2 git bundle" LF
> +
> +references   = *(prerequisite / ref) LF
> +prerequisite = "-" obj-id SP comment LF
> +comment      = *CHAR
> +ref          = obj-id SP refname LF
> +
> +pack         = ... ; packfile
> +----
> +
> +== Semantics
> +
> +A Git bundle consists of three parts.
> +
> +*   Prerequisites: Optional list of objects that are not included in the bundle
> +    file. A bundle can reference these prerequisite objects (or it can reference
> +    the objects reachable from the prerequisite objects). The bundle itself
> +    might not contain those objects.
> +*   References: Mapping of ref names to objects.
> +*   Git objects: Commit, tree, blob, and tags. These are included in the pack
> +    format.
> +
> +If a bundle contains prerequisites, it means the bundle has a thin pack and the
> +bundle alone is not enough for resolving all objects. When you read such
> +bundles, you should have those missing objects beforehand.
> +
> +In the bundle format, there can be a comment following a prerequisite obj-id.
> +This is a comment and it has no specific meaning. When you write a bundle, you
> +can put any string here. When you read a bundle, you can ignore this part.
> --
> 2.25.0.341.g760bfbb309-goog
>
>
Junio C Hamano Jan. 31, 2020, 8:38 p.m. UTC | #2
Masaya Suzuki <masayasuzuki@google.com> writes:

> The bundle format was not documented. Describe the format with ABNF and
> explain the meaning of each part.

Thanks.

>
> Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
> ---
>  Documentation/technical/bundle-format.txt | 40 +++++++++++++++++++++++
>  1 file changed, 40 insertions(+)
>  create mode 100644 Documentation/technical/bundle-format.txt
>
> diff --git a/Documentation/technical/bundle-format.txt b/Documentation/technical/bundle-format.txt
> new file mode 100644
> index 0000000000..dbb80225b5
> --- /dev/null
> +++ b/Documentation/technical/bundle-format.txt
> @@ -0,0 +1,40 @@
> += Git bundle v2 format
> +
> +The Git bundle format is a format that represents both refs and Git objects.
> +
> +== Format
> +
> +We will use ABNF notation to define the Git bundle format. See
> +protocol-common.txt for the details.
> +
> +----
> +bundle    = signature references pack
> +signature = "# v2 git bundle" LF

Good.  "signature" is the name used by bundle.c::create_bundle() to
call this part.

> +references   = *(prerequisite / ref) LF

This allows prereq and ref can come inter-mixed, but I think we show
all prerequisites first before refs.

> +prerequisite = "-" obj-id SP comment LF
> +comment      = *CHAR

Do readers know what CHAR consists of?  Anything other than NUL and
LF?

> +ref          = obj-id SP refname LF

OK.

"prerequisite" and "ref" are both used in bundle.c::create_bundle(),
so calling these parts with these names is consistent with the code.
"head" is also a good name for the latter as "git bundle list-heads"
is the way the end-users access them from outside.

> +
> +pack         = ... ; packfile
> +----
> +
> +== Semantics
> +
> +A Git bundle consists of three parts.
> +
> +*   Prerequisites: Optional list of objects that are not included in the bundle
> +    file. A bundle can reference these prerequisite objects (or it can reference
> +    the objects reachable from the prerequisite objects). The bundle itself
> +    might not contain those objects.

While not incorrect per-se, the above misses the more important
points (and defers the description to a later paragraph).  It is
better to describe what it means to have prereqs upfront.  

> +*   References: Mapping of ref names to objects.
> +*   Git objects: Commit, tree, blob, and tags. These are included in the pack
> +    format.
> +

Match the name you used to descibe the parts in the earlier ABNF
description, so that the correspondence is clear to the readers.
You somehow used "references" to mean both prereqs and heads, but in
the above you are describing only "heads" under the label of
"references".

Perhaps something like this?

    * "Prerequisites" lists the objects that are NOT included in the
      bundle and the receiver of the bundle MUST already have, in
      order to use the data in the bundle.  The objects stored in
      the bundle may refer to prerequiste objects and anything
      reachable from them and/or expressed as a delta against
      prerequisite objects.

    * "Heads" record the tips of the history graph, iow, what the
      receiver of the bundle CAN "git fetch" from it.

    * "Pack" is the pack data stream "git fetch" would send, if you
      fetch from a repository that has the references recorded in
      the "Heads" above into a repository that has references
      pointing at the objects listed in "Prerequisites" above.

> +If a bundle contains prerequisites, it means the bundle has a thin pack and the
> +bundle alone is not enough for resolving all objects. When you read such
> +bundles, you should have those missing objects beforehand.

With the above rewrite, this paragraph is unneeded.

> +In the bundle format, there can be a comment following a prerequisite obj-id.
> +This is a comment and it has no specific meaning. When you write a bundle, you
> +can put any string here. When you read a bundle, you can ignore this part.

Is it "you can"?  At least the last one should be "readers of a
bundle MUST ignore the comment", I think.
Masaya Suzuki Jan. 31, 2020, 9:49 p.m. UTC | #3
On Fri, Jan 31, 2020 at 12:38 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Masaya Suzuki <masayasuzuki@google.com> writes:
>
> > The bundle format was not documented. Describe the format with ABNF and
> > explain the meaning of each part.
>
> Thanks.
>
> >
> > Signed-off-by: Masaya Suzuki <masayasuzuki@google.com>
> > ---
> >  Documentation/technical/bundle-format.txt | 40 +++++++++++++++++++++++
> >  1 file changed, 40 insertions(+)
> >  create mode 100644 Documentation/technical/bundle-format.txt
> >
> > diff --git a/Documentation/technical/bundle-format.txt b/Documentation/technical/bundle-format.txt
> > new file mode 100644
> > index 0000000000..dbb80225b5
> > --- /dev/null
> > +++ b/Documentation/technical/bundle-format.txt
> > @@ -0,0 +1,40 @@
> > += Git bundle v2 format
> > +
> > +The Git bundle format is a format that represents both refs and Git objects.
> > +
> > +== Format
> > +
> > +We will use ABNF notation to define the Git bundle format. See
> > +protocol-common.txt for the details.
> > +
> > +----
> > +bundle    = signature references pack
> > +signature = "# v2 git bundle" LF
>
> Good.  "signature" is the name used by bundle.c::create_bundle() to
> call this part.
>
> > +references   = *(prerequisite / ref) LF
>
> This allows prereq and ref can come inter-mixed, but I think we show
> all prerequisites first before refs.

Based on bundle.c::parse_bundle_header(), I infer that this can be
mixed. If that's not intended, this can be changed to have
prerequisites first.

>
> > +prerequisite = "-" obj-id SP comment LF
> > +comment      = *CHAR
>
> Do readers know what CHAR consists of?  Anything other than NUL and
> LF?

RFC 5234 defines core rules
(https://tools.ietf.org/html/rfc5234#appendix-B.1), and these CHAR etc
are defined there. It should be OK to use these rules.

>
> > +ref          = obj-id SP refname LF
>
> OK.
>
> "prerequisite" and "ref" are both used in bundle.c::create_bundle(),
> so calling these parts with these names is consistent with the code.
> "head" is also a good name for the latter as "git bundle list-heads"
> is the way the end-users access them from outside.
>
> > +
> > +pack         = ... ; packfile
> > +----
> > +
> > +== Semantics
> > +
> > +A Git bundle consists of three parts.
> > +
> > +*   Prerequisites: Optional list of objects that are not included in the bundle
> > +    file. A bundle can reference these prerequisite objects (or it can reference
> > +    the objects reachable from the prerequisite objects). The bundle itself
> > +    might not contain those objects.
>
> While not incorrect per-se, the above misses the more important
> points (and defers the description to a later paragraph).  It is
> better to describe what it means to have prereqs upfront.
>
> > +*   References: Mapping of ref names to objects.
> > +*   Git objects: Commit, tree, blob, and tags. These are included in the pack
> > +    format.
> > +
>
> Match the name you used to descibe the parts in the earlier ABNF
> description, so that the correspondence is clear to the readers.
> You somehow used "references" to mean both prereqs and heads, but in
> the above you are describing only "heads" under the label of
> "references".

Yes. It should match with the ABNF definition above.

I usually use "heads" to mean "references under refs/heads/*" (not
sure if this is true for other people). Since a bundle can contain
tags etc., using "heads" here seems confusing. With prerequisites and
references split you mentioned above, I think I can make ABNF and this
semantics section consistent in terms of wording.

bundle = signature *prerequisite *ref LF pack
prerequisite = "-" obj-id SP comment LF
comment = *CHAR
reference = obj-id SP refname LF
pack = ... ; packfile

The terms ("prerequisite" and "reference") are consistent with
bundle.h::ref_list.

>
> Perhaps something like this?
>
>     * "Prerequisites" lists the objects that are NOT included in the
>       bundle and the receiver of the bundle MUST already have, in
>       order to use the data in the bundle.  The objects stored in
>       the bundle may refer to prerequiste objects and anything
>       reachable from them and/or expressed as a delta against
>       prerequisite objects.

I want to make sure the meaning of prerequisites.

1. Are they meant for a delta base? Or are they meant to represent a
partial/shallow state?

If these prerequisites are used as a delta base, the receiver of the
bundle MUST have them. If these prerequisites are the indicators of
the shallowness or the partialness of the repository, the pack data
would have complete data in terms of deltification (e.g. all objects
in the pack file can be undeltified with just the pack file), and the
bundle can be treated as a shallow-cloned/partially-cloned repository
snapshot.

From what I can see from bundle.c, I think it's an indicator of a
delta base, not an indicator of a shallow/partial state, but I want to
make sure.

2. Do they need to be commits? Or can they be any object type?

From what I can see, it seems that they should always be commits.

3. Does the receiver have to have all reachable objects from prerequisites?

My understanding is "Yes, the receiver must have all reachable objects
from prerequisites." This means that if a receiver has a
shallow-cloned repository, they might not be able to proceess a bundle
with prerequisites. The bundle's pack part can deltify against the
objects that exist beyond the shallow depth.

>
>     * "Heads" record the tips of the history graph, iow, what the
>       receiver of the bundle CAN "git fetch" from it.
>
>     * "Pack" is the pack data stream "git fetch" would send, if you
>       fetch from a repository that has the references recorded in
>       the "Heads" above into a repository that has references
>       pointing at the objects listed in "Prerequisites" above.

I'll adopt this in the next patch.

>
> > +If a bundle contains prerequisites, it means the bundle has a thin pack and the
> > +bundle alone is not enough for resolving all objects. When you read such
> > +bundles, you should have those missing objects beforehand.
>
> With the above rewrite, this paragraph is unneeded.
>
> > +In the bundle format, there can be a comment following a prerequisite obj-id.
> > +This is a comment and it has no specific meaning. When you write a bundle, you
> > +can put any string here. When you read a bundle, you can ignore this part.
>
> Is it "you can"?  At least the last one should be "readers of a
> bundle MUST ignore the comment", I think.

I'll change this to MUST.
Junio C Hamano Jan. 31, 2020, 11:01 p.m. UTC | #4
Masaya Suzuki <masayasuzuki@google.com> writes:

>> > +prerequisite = "-" obj-id SP comment LF
>> > +comment      = *CHAR
>>
>> Do readers know what CHAR consists of?  Anything other than NUL and
>> LF?
>
> RFC 5234 defines core rules
> (https://tools.ietf.org/html/rfc5234#appendix-B.1), and these CHAR etc
> are defined there. It should be OK to use these rules.

That's not what I asked.  Do readers know that?  Did you tell them
that we expect they are familiar with the RFC convention?

It might be easier to make the above simple ABNF understandable to
those without knowledge of RFC 5234 by spelling out what CHAR in the
context of the above description means.  Or to tell them "go over
there and learn CHAR then come back".  We need to do one of them.

> I want to make sure the meaning of prerequisites.
>
> 1. Are they meant for a delta base? Or are they meant to represent a
> partial/shallow state?

They are meant as the "bottom boundary" of the range of the pack
data stored in the bundle.

Think of "git rev-list --objects $heads --not $prerequisites".  If
we limit ourselves to commits, in the simplest case, "git log
maint..master".  Imagine your repository has everything up to
'maint' (and nothing else) and then you are "git fetch"-ing from
another repository that advanced the tip that now points at
'master'.  Imagine the data transferred over the network.  Imagine
that data is frozen on disk somehow.  That is what a bundle is.

So, 'maint' is the prerequisite---for the person who builds the
bundle, it can safely be assumed that the bundle will be used only
by those who already has 'maint'.

There is nothing about 'partial' or 'shallow'.  And even though a
bundle typically has deltified objects in the packfile, it does not
have to.  Some objects are delitifed against prerequisite, and the
logic to generate thin packs may even prefer to use the
prerequisites as the delta base, but it is merely a side effect that
the prerequisites are at the "bottom boundary" of the range.

> 2. Do they need to be commits? Or can they be any object type?
>
> From what I can see, it seems that they should always be commits.
>
> 3. Does the receiver have to have all reachable objects from prerequisites?

I would say that the receiver needs to have everything that is
needed to "complete" prereqs.

Bundle transfer predates shallow or incomplete repositories, but I
think that we can (and we should if needed) update it to adjust to
these situations by using the appropriate definition of what it
means to "complete".  In a lazy clone, it may be sufficient to have
promisor remote that has everything reachable from them.  In a
shallow clone, the repository may have to be deep enough to have
them and objects immediately reachable from them (e.g. trees and
blobs for a commit at the "bottom boundary").

Thanks.
Masaya Suzuki Jan. 31, 2020, 11:57 p.m. UTC | #5
On Fri, Jan 31, 2020 at 3:01 PM Junio C Hamano <gitster@pobox.com> wrote:
>
> Masaya Suzuki <masayasuzuki@google.com> writes:
>
> >> > +prerequisite = "-" obj-id SP comment LF
> >> > +comment      = *CHAR
> >>
> >> Do readers know what CHAR consists of?  Anything other than NUL and
> >> LF?
> >
> > RFC 5234 defines core rules
> > (https://tools.ietf.org/html/rfc5234#appendix-B.1), and these CHAR etc
> > are defined there. It should be OK to use these rules.
>
> That's not what I asked.  Do readers know that?  Did you tell them
> that we expect they are familiar with the RFC convention?

The patch says "We will use ABNF notation to define the Git bundle
format. See protocol-common.txt for the details.", and
protocol-common.txt says "ABNF notation as described by RFC 5234 is
used within the protocol documents, except the following replacement
core rules are used:". In order to interpret this ABNF definition,
it's not enough to read RFC 5234, but the reader has to read
protocol-common.txt. Otherwise, they cannot understand what `obj-id`
is and what `refname` is. Those are not defined in RFC 5234. They're
defined in protocol-common.txt.

Based on the fact that (1) this document instructs the reader to see
protocol-common.txt in the beginning and (2) protocol-common.txt is
needed to interpret this definition and protocol-common.txt says RFC
5234 describes ABNF format, the readers should know ABNF is defined in
RFC 5234 and ABNF includes those LF, CHAR, and SP as a part of the
definition after reading the first sentence and referenced documents.

>
> It might be easier to make the above simple ABNF understandable to
> those without knowledge of RFC 5234 by spelling out what CHAR in the
> context of the above description means.  Or to tell them "go over
> there and learn CHAR then come back".  We need to do one of them.

As I said above, the first sentence says "See protocol-common.txt"
which includes the reference to the RFC and other non-terminals. Note
that, not only CHAR, but obj-id and refname are not defined here as
well. The readers need to reference protocol-common.txt to get the
definition of them.

>
> > I want to make sure the meaning of prerequisites.
> >
> > 1. Are they meant for a delta base? Or are they meant to represent a
> > partial/shallow state?
>
> They are meant as the "bottom boundary" of the range of the pack
> data stored in the bundle.
>
> Think of "git rev-list --objects $heads --not $prerequisites".  If
> we limit ourselves to commits, in the simplest case, "git log
> maint..master".  Imagine your repository has everything up to
> 'maint' (and nothing else) and then you are "git fetch"-ing from
> another repository that advanced the tip that now points at
> 'master'.  Imagine the data transferred over the network.  Imagine
> that data is frozen on disk somehow.  That is what a bundle is.
>
> So, 'maint' is the prerequisite---for the person who builds the
> bundle, it can safely be assumed that the bundle will be used only
> by those who already has 'maint'.
>
> There is nothing about 'partial' or 'shallow'.  And even though a
> bundle typically has deltified objects in the packfile, it does not
> have to.  Some objects are delitifed against prerequisite, and the
> logic to generate thin packs may even prefer to use the
> prerequisites as the delta base, but it is merely a side effect that
> the prerequisites are at the "bottom boundary" of the range.

OK. Then, it's better to make this clear. If you follow the analogy of
saved git-fetch response, it's possible that these prerequisites are
interpreted same as "shallow" lines of the shallow clone response.
It's more like "have" lines of git-fetch request.

> > 2. Do they need to be commits? Or can they be any object type?
> >
> > From what I can see, it seems that they should always be commits.
> >
> > 3. Does the receiver have to have all reachable objects from prerequisites?
>
> I would say that the receiver needs to have everything that is
> needed to "complete" prereqs.
>
> Bundle transfer predates shallow or incomplete repositories, but I
> think that we can (and we should if needed) update it to adjust to
> these situations by using the appropriate definition of what it
> means to "complete".  In a lazy clone, it may be sufficient to have
> promisor remote that has everything reachable from them.  In a
> shallow clone, the repository may have to be deep enough to have
> them and objects immediately reachable from them (e.g. trees and
> blobs for a commit at the "bottom boundary").

I think there are two completeness of a packfile:

* Delta complete: If an object in a packfile is deltified, the delta
base exists in the same packfile.
* Object complete: If an object in a packfile contains a reference to
another object, that object exists in the same packfile.

For example, initial shallow clone response should contain a
delta-complete object-incomplete packfile. Incremental fetch response
and bundles with prereqs would have a delta-incomplete
object-incomplete packfile. Creating delta-incomplete object-complete
packfile is possible (e.g. create a parallel history with all blobs
slightly modified and deltify against the original branch. I can
create a packfile with all objects in one history with all objects
deltified with the other history), but it's a rare case.

The reader of a bundle SHOULD have all objects reachable from prereqs.
Junio C Hamano Feb. 4, 2020, 6:20 p.m. UTC | #6
Masaya Suzuki <masayasuzuki@google.com> writes:

> * Delta complete: If an object in a packfile is deltified, the delta
> base exists in the same packfile.

Yes, even though "thin" packs delierately violate this to save size,
normal packs, and more importantly, on-disk packs, are complete in
this sense.

> * Object complete: If an object in a packfile contains a reference to
> another object, that object exists in the same packfile.

A single packfile that would result from a full clone at some time
in the project's history would be "complete" in this sense.  Such a
packfile may contain all objects that are needed to reproduce the
history up to v1.0.1, or another larger "object complete" packfile
may contain everything needed for the history up to v3.0.0.  So as a
concept, this can be defined sensibly.  In the original packfile
design, however, this concept was not useful (iow, there was nowhere
that cared if a packfile is "object complete" or not), so I do not
think there is no explicit "support" to ensure or validate this
trait in the system.

Obviously, a bundle that stores object incomplete pack must have
been created with the bottom boundary.

> The reader of a bundle SHOULD have all objects reachable from prereqs.

Perhaps.  

It _might_ be possible to teach "git clone" to produce a shallow
clone whose shallow cut-off points match the prerequisites of the
bundle, so it depends on what the reader wants to do with the data,
though.

Thanks.

Patch
diff mbox series

diff --git a/Documentation/technical/bundle-format.txt b/Documentation/technical/bundle-format.txt
new file mode 100644
index 0000000000..dbb80225b5
--- /dev/null
+++ b/Documentation/technical/bundle-format.txt
@@ -0,0 +1,40 @@ 
+= Git bundle v2 format
+
+The Git bundle format is a format that represents both refs and Git objects.
+
+== Format
+
+We will use ABNF notation to define the Git bundle format. See
+protocol-common.txt for the details.
+
+----
+bundle    = signature references pack
+signature = "# v2 git bundle" LF
+
+references   = *(prerequisite / ref) LF
+prerequisite = "-" obj-id SP comment LF
+comment      = *CHAR
+ref          = obj-id SP refname LF
+
+pack         = ... ; packfile
+----
+
+== Semantics
+
+A Git bundle consists of three parts.
+
+*   Prerequisites: Optional list of objects that are not included in the bundle
+    file. A bundle can reference these prerequisite objects (or it can reference
+    the objects reachable from the prerequisite objects). The bundle itself
+    might not contain those objects.
+*   References: Mapping of ref names to objects.
+*   Git objects: Commit, tree, blob, and tags. These are included in the pack
+    format.
+
+If a bundle contains prerequisites, it means the bundle has a thin pack and the
+bundle alone is not enough for resolving all objects. When you read such
+bundles, you should have those missing objects beforehand.
+
+In the bundle format, there can be a comment following a prerequisite obj-id.
+This is a comment and it has no specific meaning. When you write a bundle, you
+can put any string here. When you read a bundle, you can ignore this part.