All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Update packfile transfer protocol documentation
@ 2009-11-04  5:58 Scott Chacon
  2009-11-04  6:36 ` Sverre Rabbelier
  2009-11-05  5:24 ` Junio C Hamano
  0 siblings, 2 replies; 25+ messages in thread
From: Scott Chacon @ 2009-11-04  5:58 UTC (permalink / raw)
  To: git list; +Cc: Junio C Hamano, Shawn O. Pearce

The technical documentation for the packfile protocol is both sparse and
incorrect.  This documents the fetch-pack/upload-pack and send-pack/
receive-pack protocols much more fully.

Add documentation from Shawn's upcoming http-protocol docs that is shared
by the packfile protocol. protocol-common.txt describes ABNF notation
amendments, refname rules and the packet line format.

Add documentation on the various capabilities supported by the
upload-pack and receive-pack protocols. protocol-capabilities.txt describes
multi-ack, thin-pack, side-band[-64k], shallow, no-progress, include-tag,
ofs-delta, delete-refs and report-status.

Signed-off-by: Scott Chacon <schacon@gmail.com>
---

OK, I think I've incorporated all the comments from you and Shawn
here.  Let me know if that's cool or you need me to update anything
else.

 Documentation/technical/pack-protocol.txt         |  535 +++++++++++++++++++--
 Documentation/technical/protocol-capabilities.txt |  186 +++++++
 Documentation/technical/protocol-common.txt       |   96 ++++
 3 files changed, 776 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/technical/protocol-capabilities.txt
 create mode 100644 Documentation/technical/protocol-common.txt

diff --git a/Documentation/technical/pack-protocol.txt
b/Documentation/technical/pack-protocol.txt
index 9cd48b4..4b476da 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -1,41 +1,494 @@
-Pack transfer protocols
-=======================
-
-There are two Pack push-pull protocols.
-
-upload-pack (S) | fetch/clone-pack (C) protocol:
-
-	# Tell the puller what commits we have and what their names are
-	S: SHA1 name
-	S: ...
-	S: SHA1 name
-	S: # flush -- it's your turn
-	# Tell the pusher what commits we want, and what we have
-	C: want name
-	C: ..
-	C: want name
-	C: have SHA1
-	C: have SHA1
-	C: ...
-	C: # flush -- occasionally ask "had enough?"
-	S: NAK
-	C: have SHA1
-	C: ...
-	C: have SHA1
-	S: ACK
-	C: done
-	S: XXXXXXX -- packfile contents.
-
-send-pack | receive-pack protocol.
-
-	# Tell the pusher what commits we have and what their names are
-	C: SHA1 name
-	C: ...
-	C: SHA1 name
-	C: # flush -- it's your turn
-	# Tell the puller what the pusher has
-	S: old-SHA1 new-SHA1 name
-	S: old-SHA1 new-SHA1 name
-	S: ...
-	S: # flush -- done with the list
-	S: XXXXXXX --- packfile contents.
+Packfile transfer protocols
+===========================
+
+Git supports transferring data in packfiles over the ssh://, git:// and
+file:// transports.  There exist two sets of protocols, one for pushing
+data from a client to a server and another for fetching data from a
+server to a client.  All three transports (ssh, git, file) use the same
+protocol to transfer data.
+
+The processes invoked in the canonical Git implementation are 'upload-pack'
+on the server side and 'fetch-pack' on the client side for fetching data;
+then 'receive-pack' on the server and 'send-pack' on the client for pushing
+data.  The protocol functions to have a server tell a client what is
+currently on the server, then for the two to negotiate the smallest amount
+of data to send in order to fully update one or the other.
+
+Transports
+----------
+There are three transports over which the packfile protocol is
+initiated.  The Git transport is a simple, unauthenticated server that
+takes the command (almost always 'upload-pack', though Git
+servers can be configured to be globally writable, in which 'receive-
+pack' initiation is also allowed) with which the client wishes to
+communicate and executes it and connects it to the requesting
+process.
+
+In the SSH transport, the client just runs the 'upload-pack'
+or 'receive-pack' process on the server over the SSH protocol and then
+communicates with that invoked process over the SSH connection.
+
+The file:// transport runs the 'upload-pack' or 'receive-pack'
+process locally and communicates with it over a pipe.
+
+Git Transport
+-------------
+
+The Git protocol starts off by sending the command and repository
+on the wire using the pkt-line format, followed by a null byte and a
+hostname paramater, terminated by a null byte.
+
+   0032git-upload-pack /project.git\0host=myserver.com\0
+
+--
+   git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
+   request-command   = "git-upload-pack" / "git-receive-pack" /
+                       "git-upload-archive"   ; case sensitive
+   pathname          = *( %x01-ff ) ; exclude NUL
+   host-parameter    = "host=" hostname [ ":" port ]
+--
+
+Only host-parameter is allowed in the git-proto-request. Clients
+MUST NOT attempt to send additional parameters. It is used for the
+git-daemon name based virtual hosting.  See --interpolated-path
+option to git daemon, with the %H/%CH format characters.
+
+Basically what the Git client is doing to connect to an 'upload-pack'
+process on the server side over the Git protocol is this:
+
+   $ echo -e -n \
+     "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+     nc -v example.com 9418
+
+
+SSH Transport
+-------------
+
+Initiating the upload-pack or receive-pack processes over SSH is
+executing the binary on the server via SSH remote execution.
+It is basically equivalent to running this:
+
+   $ ssh git.example.com "git-upload-pack '/project.git'"
+
+For a server to support Git pushing and pulling for a given user over
+SSH, that user needs to be able to execute one or both of those
+commands via the SSH shell that they are provided on login.  On some
+systems, that shell access is limited to only being able to run those
+two commands, or even just one of them.
+
+In an ssh:// format URI, it's absolute in the URI, so the '/' after
+the host name (or port number) is sent as an argument, which is then
+read by the remote git-upload-pack exactly as is, so it's effectively
+an absolute path in the remote filesystem.
+
+       git clone ssh://user@example.com/project.git
+                    |
+                    v
+    ssh user@example.com "git-upload-pack '/project.git'"
+
+In a "user@host:path" format URI, its relative to the user's home
+directory, because the Git client will run:
+
+     git clone user@example.com:project.git
+                    |
+                    v
+  ssh user@example.com "git-upload-pack 'project.git'"
+
+The exception is if a '~' is used, in which case
+we execute it without the leading '/'.
+
+      ssh://user@example.com/~alice/project.git,
+                     |
+                     v
+   ssh user@example.com "git-upload-pack '~alice/project.git'"
+
+A few things to remember here:
+
+- The "command name" is spelled with dash (e.g. git-upload-pack), but
+  this can be overridden by the client;
+
+- The repository path is always quoted with single quotes.
+
+Fetching Data From a Server
+===========================
+
+When one Git repository wants to get data that a second repository
+has, the first can 'fetch' from the second.  This operation determines
+what data the server has that the client does not then streams that
+data down to the client in packfile format.
+
+
+Reference Discovery
+-------------------
+
+When the client initially connects the server will immediately respond
+with a listing of each reference it has (all branches and tags) along
+with the object name that each reference currently points to.
+
+   $ echo -e -n "0039git-upload-pack
/schacon/gitbook.git\0host=example.com\0" |
+      nc -v example.com 9418
+   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack
thin-pack side-band side-band-64k ofs-delta shallow no-progress
include-tag
+   00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
+   003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
+   003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
+   003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
+   003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
+   0000
+
+Server SHOULD terminate each non-flush line using LF ("\n") terminator;
+client MUST NOT complain if there is no terminator.
+
+The returned response is a pkt-line stream describing each ref and
+its known value.  The stream MUST be sorted by name according to
+the C locale ordering.
+
+If HEAD is a valid ref, HEAD MUST appear as the first advertised
+ref.  If HEAD is not a valid ref, HEAD MUST NOT appear in the
+advertisement list at all, but other refs may still appear.
+
+The stream MUST include capability declarations behind a NUL on the
+first ref. The peeled value of a ref (that is "ref^{}") MUST be
+immediately after the ref itself, if presented. A conforming server
+MUST peel the ref if its an annotated tag.
+
+----
+  advertised-refs  =  (no-refs / list-of-refs)
+                      flush-pkt
+
+  no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
+                      NUL capability-list LF)
+
+  list-of-refs     =  first-ref *other-ref
+  first-ref        =  PKT-LINE(obj-id SP refname
+                      NUL capability-list LF)
+
+  other-ref        =  PKT-LINE(other-tip / other-peeled)
+  other-tip        =  obj-id SP refname LF
+  other-peeled     =  obj-id SP refname "^{}" LF
+
+  capability-list  =  capability *(SP capability)
+  capability       =  1*(LC_ALPHA / DIGIT / "-" / "_")
+  LC_ALPHA         =  %x61-7A
+----
+
+Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
+as case-insensitive.
+
+See protocol-capabilities.txt for a list of allowed server capabilities
+and descriptions.
+
+Packfile Negotiation
+--------------------
+After reference and capabilities discovery, the client can decide
+to terminate the connection by sending a flush-pkt, telling the
+server it can now gracefully terminate (as happens with the ls-remote
+command) or it can enter the negotiation phase, where the client and
+server determine what the minimal packfile necessary for transport is.
+
+Once the client has the initial list of references that the server
+has, as well as the list of capabilities, it will begin telling the
+server what objects it wants and what objects it has, so the server
+can make a packfile that only has the objects that the client needs.
+The client will also send a list of the capabilities it supports out
+of what the server said it could do with the first 'want' line.
+
+----
+  upload-request    =  want-list
+                       have-list
+                       compute-end
+
+  want-list         =  first-want
+                       *additional-want
+                       flush-pkt
+
+  first-want        =  PKT-LINE("want" SP obj-id SP capability-list LF)
+  additional-want   =  PKT-LINE("want" SP obj-id LF)
+
+  have-list         =  *have-line
+  have-line         =  PKT-LINE("have" SP obj-id LF)
+  compute-end       =  flush-pkt / PKT-LINE("done")
+----
+
+Clients MUST send all the obj-ids it wants from the reference
+discovery phase as 'want' lines. Clients MUST send at least one
+'want' command in the request body. Clients MUST NOT mention an
+obj-id in a 'want' command which did not appear in the response
+obtained through ref discovery.
+
+If client is requesting a shallow clone, it will now send a 'deepen'
+line with the depth it is requesting.
+
+Once all the "want"s (and optional 'deepen') are transferred,
+clients MUST send a flush-pkt. If the client has all the references
+on the server, client flushes and disconnects.
+
+TODO: shallow/unshallow response and document the deepen command in the ABNF.
+
+Now the client will send a list of the obj-ids it has using 'have'
+lines.  In multi_ack mode, the canonical implementation will send up
+to 32 of these at a time, then will send a flush-pkt.  The canonical
+implementation will skip ahead and send the next 32 immediately,
+so that there is always a block of 32 "in-flight on the wire" at a
+time.
+
+If the server reads 'have' lines, it then will respond by ACKing any
+of the obj-ids the client said it had that the server also has. The
+server will ACK obj-ids differently depending on which ack mode is
+signaled by the client.
+
+In multi_ack mode:
+
+  * the server will respond with 'ACK obj-id continue' for any common
+    commits.
+
+  * once the server has found an acceptable common base commit and is
+    ready to make a packfile, it will blindly ACK all 'have' obj-ids
+    back to the client.
+
+  * the server will then send a 'NACK' and then wait for another response
+    from the client - either a 'done' or another list of 'have' lines.
+
+In multi_ack_detailed mode:
+
+  * the server will differentiate the ACKs where it is signaling
+    that it is ready to send data with 'ACK obj-id ready' lines, and
+    signals the identified common commits with 'ACK obj-id common' lines.
+
+Without multi_ack:
+
+ * upload-pack sends "ACK obj-id" on the first common object it finds.
+   After that it says nothing until the client gives it a "done".
+
+ * upload-pack sends "NAK" on a flush-pkt if no common object
+   has been found yet.  If one has been found, and thus an ACK
+   was already sent, its silent on the flush-pkt.
+
+After the client has gotten enough ACK responses that it can determine
+that the server has enough information to send an efficient packfile
+(in the canonical implementation, this is determined when it has received
+enough ACKs that it can color everything left in the --date-order queue
+as common with the server, or the --date-order queue is empty), or the
+client determines that it wants to give up (in the canonical implementation,
+this is determined when the client sends 256 'have' lines without getting
+any of them ACKed by the server - meaning there is nothing in common and
+the server should just send all it's objects), then the client will send
+a 'done' command.  The 'done' command signals to the server that the client
+is ready to receive it's packfile data.
+
+However, the 256 limit *only* turns on in the canonical client
+implementation if we have received at least one "ACK %s continue"
+during a prior round.  This helps to ensure that at least one common
+ancestor is found before we give up entirely.
+
+Once the 'done' line is read from the client, the server will either
+send a final 'ACK obj-id' or it will send a 'NAK'. The server only sends
+ACK after 'done' if there is at least one common base and multi_ack or
+multi_ack_detailed is enabled. The server always sends NAK after 'done'
+if there is no common base found.
+
+Then the server will start sending it's packfile data.
+
+----
+  server-response = *ack_multi ack / nak
+  ack_multi       = PKT-LINE("ACK" SP obj-id ack_status LF)
+  ack_status      = "continue" / "common" / "ready"
+  ack             = PKT-LINE("ACK SP obj-id LF)
+  nak             = PKT-LINE("NAK" LF)
+----
+
+A simple clone may look like this (with no 'have' lines):
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+   C: 0009done\n
+
+   S: 0008NAK\n
+   S: [PACKFILE]
+----
+
+An incremental update (fetch) response might look like this:
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0000
+   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: [30 more have lines]
+   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+
+   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
+   S: 0008NAK\n
+
+   C: 0009done\n
+
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   S: [PACKFILE]
+----
+
+
+Packfile Data
+-------------
+
+Now that the client and server have done some negotiation about what
+the minimal amount of data that can be sent to the client is, the server
+will construct and send the required data in packfile format.
+
+See pack-format.txt for what the packfile itself actually looks like.
+
+If 'side-band' or 'side-band-64k' capabilities have been specified by
+the client, the server will send the packfile data multiplexed.
+
+Each packet starting with the packet-line length of the amount of data
+that follows, followed by a single byte specifying the sideband the
+following data is coming in on.
+
+In 'side-band' mode, it will send up to 999 data bytes plus 1 control
+code, for a total of up to 1000 bytes in a pkt-line.  In 'side-band-64k'
+mode it will send up to 65519 data bytes plus 1 control code, for a
+total of up to 65520 bytes in a pkt-line.
+
+The sideband byte will be a '1', '2' or a '3'. Sideband '1' will contain
+packfile data, sideband '2' will be used for progress information that the
+client will generally print to stderr and sideband '3' is used for error
+information.
+
+If no 'side-band' capability was specified, the server will stream the
+entire packfile without multiplexing.
+
+
+Pushing Data To a Server
+========================
+
+Pushing data to a server will invoke the 'receive-pack' process on the
+server, which will allow the client to tell it which references it should
+update and then send all the data the server will need for those new
+references to be complete.  Once all the data is received and validated,
+the server will then update it's references to what the client specified.
+
+Authentication
+--------------
+
+The protocol itself contains no authentication mechanisms.  That is to be
+handled by the transport, such as SSH, before the 'receive-pack' process is
+invoked.  If 'receive-pack' is configured over the Git transport, those
+repositories will be writable by anyone who can access that port (9418) as
+that transport is unauthenticated.
+
+Reference Discovery
+-------------------
+
+The reference discovery phase is done nearly the same way as it is in the
+fetching protocol. Each reference obj-id and name on the server is sent
+in packet-line format to the client, followed by a flush packet.  The only
+real difference is that the capability listing is different - the only
+possible values are 'report-status', 'delete-refs' and 'ofs-delta'.
+
+Reference Update Request and Packfile Transfer
+----------------------------------------------
+
+Once the client knows what references the server is at, it can send a
+list of reference update requests.  For each reference on the server
+that it wants to update, it sends a line listing the obj-id currently on
+the server, the obj-id the client would like to update it to and the name
+of the reference.
+
+This list is followed by a flush packet and then the packfile that should
+contain all the objects that the server will need to complete the new
+references.
+
+----
+  update-request    =  command-list [pack-file]
+
+  command-list      =  PKT-LINE(command NUL capability-list LF)
+                       *PKT-LINE(command LF)
+                       flush-pkt
+
+  command           =  create / delete / update
+  create            =  zero-id SP new-id  SP name
+  delete            =  old-id  SP zero-id SP name
+  update            =  old-id  SP new-id  SP name
+
+  old-id            =  obj-id
+  new-id            =  obj-id
+
+  pack-file         = "PACK" 28*(OCTET)
+----
+
+If the receiving end does not support delete-refs, the sending end MUST
+NOT ask for delete command.
+
+The pack-file MUST NOT be sent if the only command used is 'delete'.
+
+A pack-file MUST be sent if either create or update command is used,
+even if the server already has all the necessary objects.  In this
+case the client MUST send an empty pack-file.   The only time this
+is likely to happen is if the client is doing something like creating
+a new branch that points to an existing obj-id.
+
+The server will receive the packfile, unpack it, then validate each
+reference that is being updated that it hasn't changed while the request
+was being processed (the obj-id is still the same as the old-id), and
+it will run any update hooks to make sure that the update is acceptable.
+If all of that is fine, the server will then update the references.
+
+Report Status
+-------------
+
+After receiving the pack data from the sender, the client sends a
+report if 'report-status' capability was sent to the server.
+It is a short listing of what happened in that update.  It will first
+list the status of the packfile unpacking as either 'unpack ok' or
+'unpack [error]'.  Then it will list the status for each of the references
+that it tried to update.  Each line be either 'ok [refname]' if the
+update was successful, or 'ng [refname] [error]' if the update was not.
+
+----
+  report-status     = unpack-status
+                      1*(command-status)
+                      flush-pkt
+
+  unpack-status     = PKT-LINE("unpack" SP unpack-result LF)
+  unpack-result     = "ok" / error-msg
+
+  command-status    = command-ok / command-fail
+  command-ok        = PKT-LINE("ok" SP refname LF)
+  command-fail      = PKT-LINE("ng" SP refname SP error-msg LF)
+
+  error-msg         = 1*(OCTECT) ; where not "ok"
+----
+
+Updates can be unsuccessful for a number of reasons.  The reference can have
+changed since the reference discovery phase was originally sent, meaning
+someone pushed in the meantime.  The reference being pushed could be a
+non-fast-forward reference and the update hooks or configuration could be
+set to not allow that, etc.  Also, some references can be updated while others
+can be rejected.
+
+An example client/server communication might look like this:
+
+----
+   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d
refs/heads/local\0report-status delete-refs ofs-delta\n
+   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
+   S: 0000
+
+   C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe
74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
+   C: 003e74730d410fcb6603ace96f1dc55ea6196122532d
5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
+   C: 0000
+   C: [PACKDATA]
+
+   S: 000aunpack ok\n
+   S: 0014ok refs/heads/debug\n
+   S: 0026ng refs/heads/master non-fast-forward\n
+----
diff --git a/Documentation/technical/protocol-capabilities.txt
b/Documentation/technical/protocol-capabilities.txt
new file mode 100644
index 0000000..f4bf986
--- /dev/null
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -0,0 +1,186 @@
+Git Protocol Capabilities
+=========================
+
+Servers SHOULD support all capabilities defined in this document.
+
+On the very first line of the initial server response of either
+receive-pack and upload-pack the first reference is followed by
+a null byte and then a list of space delimited server capabilities.
+These allow the server to declare what it can and cannot support
+to the client.
+
+Client will then send a space separated list of capabilities it
+can support. The client SHOULD NOT ask for capabilities the server
+did not say it supports.
+
+Server MUST ignore capabilities it does not understand.  Server MUST
+NOT ignore capabilities that client requested and server advertised.
+
+The 'report-status' and 'delete-refs' capabilities are sent and
+recognized by the receive-pack (push to server) process.
+
+The 'ofs-delta' capability is sent and recognized by both upload-pack
+and receive-pack protocols.
+
+All other capabilities are only recognized by the upload-pack (fetch
+from server) process.
+
+multi_ack
+---------
+
+The 'multi_ack' capability allows the server to return "ACK obj-id
+continue" as soon as it finds a commit that it can use as a common
+base, between the client's wants and the client's have set.
+
+By sending this early, the server can potentially head off the client
+from walking any further down that particular branch of the client's
+repository history.  The client may still need to walk down other
+branches, sending have lines for those, until the server has a
+complete cut across the DAG, or the client has said "done".
+
+Without multi_ack, a client sends have lines in --date-order until
+the server has found a common base.  That means the client will send
+have lines that are already known by the server to be common, because
+they overlap in time with another branch that the server hasn't found
+a common base on yet.
+
+For example suppose the client has commits in caps that the server
+doesn't and the server has commits in lower case that the client
+doesn't, as in the following diagram:
+
+       +---- u ---------------------- x
+      /              +----- y
+     /              /
+    a -- b -- c -- d -- E -- F
+       \
+        +--- Q -- R -- S
+
+If the client wants x,y and starts out by saying have F,S, the server
+doesn't know what F,S is.  Eventually the client says "have d" and
+the server sends "ACK d continue" to let the client know to stop
+walking down that line (so don't send c-b-a), but its not done yet,
+it needs a base for x. The client keeps going with S-R-Q, until a
+gets reached, at which point the server has a clear base and it all
+ends.
+
+Without multi_ack the client would have sent that c-b-a chain anyway,
+interleaved with S-R-Q.
+
+thin-pack
+---------
+
+This capability implies that the server can send 'thin' packs, packs
+which do not contain base objects; if those base objects are available
+on client side. Client requests 'thin-pack' capability when it
+understands how to "thicken" them adding required delta bases making
+them self contained.
+
+Client MUST NOT request 'thin-pack' capability if it cannot turn thin
+packs into proper independent packs.
+
+
+side-band, side-band-64k
+------------------------
+
+This means that server can send, and client understand multiplexed
+progress reports and error info interleaved with the packfile itself.
+
+These two options are mutually exclusive. A modern client always
+favors 'side-band-64k'.
+
+Either mode indicates that the packfile data will be streamed broken
+up into packets of up to either 1000 bytes in the case of 'side_band',
+or 65520 bytes in the case of 'side_band_64k'. Each packet is made up
+of a leading 4-byte pkt-line length of how much data is in the packet,
+followed by a 1-byte stream code, followed by the actual data.
+
+The stream code can be one of:
+
+ 1 - pack data
+ 2 - progress messages
+ 3 - fatal error message just before stream aborts
+
+The "side-band-64k" capability came about as a way for newer clients
+that can handle much larger packets to request packets that are
+actually crammed nearly full, while maintaining backward compatibility
+for the older clients.
+
+Further, with side-band and its up to 1000-byte messages, it's actually
+999 bytes of payload and 1 byte for the stream code. With side-band-64k,
+same deal, you have up to 65519 bytes of data and 1 byte for the stream
+code.
+
+The client MUST send only maximum of one of "side-band" and "side-
+band-64k".  Server MUST diagnose it as an error if client requests
+both.
+
+ofs-delta
+---------
+
+Server can send, and client understand PACKv2 with delta refering to
+its base by position in pack rather than by SHA-1.  That is, they can
+send/read OBJ_OFS_DELTA (aka type 6) in a packfile.
+
+shallow
+-------
+
+This capability adds "deepen", "shallow" and "unshallow" commands to
+the  fetch-pack/upload-pack protocol so clients can request shallow
+clones.
+
+no-progress
+-----------
+
+The client was started with "git clone -q" or something, and doesn't
+want that side band 2.  Basically the client just says "I do not
+wish to receive stream 2 on sideband, so do not send it to me, and if
+you did, I will drop it on the floor anyway".  However, the sideband
+channel 3 is still used for error responses.
+
+include-tag
+-----------
+
+The 'include-tag' capability is about sending annotated tags if we are
+sending objects they point to.  If we pack an object to the client, and
+a tag object points exactly at that object, we pack the tag object too.
+In general this allows a client to get all new annotated tags when it
+fetches a branch, in a single network connection.
+
+Clients MAY always send include-tag, hardcoding it into a request when
+the server advertises this capability. The decision for a client to
+request include-tag only has to do with the client's desires for tag
+data, whether or not a server had advertised objects in the
+refs/tags/* namespace.
+
+Servers MUST pack the tags if their referrant is packed and the client
+has requested include-tags.
+
+Clients MUST be prepared for the case where a server has ignored
+include-tag and has not actually sent tags in the pack.  In such
+cases the client SHOULD issue a subsequent fetch to acquire the tags
+that include-tag would have otherwise given the client.
+
+The server SHOULD send include-tag, if it supports it, regardless
+of whether or not there are tags available.
+
+report-status
+-------------
+
+The upload-pack process can receive a 'report-status' capability,
+which tells it that the client wants a report of what happened after
+a packfile upload and reference update.  If the pushing client requests
+this capability, after unpacking and updating references the server
+will respond with whether the packfile unpacked successfully and if
+each reference was updated successfully.  If any of those were not
+successful, it will send back an error message.  See pack-protocol.txt
+for example messages.
+
+delete-refs
+-----------
+
+If the server sends back the 'delete-refs' capability, it means that
+it is capable of accepting an all-zeroed SHA-1 value as the target
+value of a reference update.  It is not sent back by the client, it
+simply informs the client that it can be sent zeroed SHA-1 values
+to delete references.
+
diff --git a/Documentation/technical/protocol-common.txt
b/Documentation/technical/protocol-common.txt
new file mode 100644
index 0000000..2dca642
--- /dev/null
+++ b/Documentation/technical/protocol-common.txt
@@ -0,0 +1,96 @@
+Documentation Common to Pack and Http Protocols
+===============================================
+
+ABNF Notation
+-------------
+
+ABNF notation as described by RFC 5234 is used within the protocol documents,
+except the following replacement core rules are used:
+----
+  HEXDIG    =  DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
+----
+
+We also define the following common rules:
+----
+  NUL       =  %x00
+  zero-id   =  40*"0"
+  obj-id    =  40*(HEXDIGIT)
+
+  refname  =  "HEAD"
+  refname /=  "refs/" <see discussion below>
+----
+
+A refname is a hierarichal octet string beginning with "refs/" and
+not violating the 'git-check-ref-format' command's validation rules.
+More specifically, they:
+
+. They can include slash `/` for hierarchical (directory)
+  grouping, but no slash-separated component can begin with a
+  dot `.`.
+
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.
+
+. They cannot have two consecutive dots `..` anywhere.
+
+. They cannot have ASCII control characters (i.e. bytes whose
+  values are lower than \040, or \177 `DEL`), space, tilde `~`,
+  caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+  or open bracket `[` anywhere.
+
+. They cannot end with a slash `/` nor a dot `.`.
+
+. They cannot end with the sequence `.lock`.
+
+. They cannot contain a sequence `@{`.
+
+. They cannot contain a `\\`.
+
+
+pkt-line Format
+---------------
+
+Much (but not all) of the payload is described around pkt-lines.
+
+A pkt-line is a variable length binary string.  The first four bytes
+of the line, the pkt-len, indicates the total length of the line,
+in hexadecimal.  The pkt-len includes the 4 bytes used to contain
+the length's hexadecimal representation.
+
+A pkt-line MAY contain binary data, so implementors MUST ensure
+pkt-line parsing/formatting routines are 8-bit clean.
+
+A non-binary line SHOULD BE terminated by an LF, which if present
+MUST be included in the total length.
+
+The maximum length of a pkt-line's data component is 65520 bytes.
+Implementations MUST NOT send pkt-line whose length exceeds 65524
+(65520 bytes of payload + 4 bytes of length data).
+
+Implementations SHOULD NOT send an empty pkt-line ("0004").
+
+A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
+is a special case and MUST be handled differently than an empty
+pkt-line ("0004").
+
+----
+  pkt-line     =  data-pkt / flush-pkt
+
+  data-pkt     =  pkt-len pkt-payload
+  pkt-len      =  4*(HEXDIG)
+  pkt-payload  =  (pkt-len - 4)*(OCTET)
+
+  flush-pkt    = "0000"
+----
+
+Examples (as C-style strings):
+
+----
+  pkt-line          actual value
+  ---------------------------------
+  "0006a\n"         "a\n"
+  "0005a"           "a"
+  "000bfoobar\n"    "foobar\n"
+  "0004"            ""
+----
-- 
1.6.5.2.340.g000a3e

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  5:58 [PATCH] Update packfile transfer protocol documentation Scott Chacon
@ 2009-11-04  6:36 ` Sverre Rabbelier
  2009-11-05  5:24 ` Junio C Hamano
  1 sibling, 0 replies; 25+ messages in thread
From: Sverre Rabbelier @ 2009-11-04  6:36 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Junio C Hamano, Shawn O. Pearce

Heya,

On Wed, Nov 4, 2009 at 06:58, Scott Chacon <schacon@gmail.com> wrote:
> The technical documentation for the packfile protocol is both sparse and incorrect

Each time I read this line I read:

"This technical documentation for the packfile protocol is both sparse
and incorrect"

Perhaps if there is another resend after this you can change it to:

"The current technical documentation for the packfile protocol is both sparse"

-- 
Cheers,

Sverre Rabbelier

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  5:58 [PATCH] Update packfile transfer protocol documentation Scott Chacon
  2009-11-04  6:36 ` Sverre Rabbelier
@ 2009-11-05  5:24 ` Junio C Hamano
       [not found]   ` <20091111171924.6117@nanako3.lavabit.com>
  1 sibling, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-05  5:24 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Junio C Hamano, Shawn O. Pearce

Scott Chacon <schacon@gmail.com> writes:

> The technical documentation for the packfile protocol is both sparse and
> incorrect.  This documents the fetch-pack/upload-pack and send-pack/
> receive-pack protocols much more fully.

Thanks.

In this round, my comments ended up being mostly "nit-picky", although I
spotted a few logic errors.

> +Git Transport
> +-------------
> +
> +The Git protocol starts off by sending the command and repository

"transport"

> +on the wire using the pkt-line format, followed by a null byte and a
> +hostname paramater, terminated by a null byte.

The name of the byte whose value is 0 is "NUL", not "NULL" (as you
correctly did in the "Reference Discovery" section).

> +Basically what the Git client is doing to connect to an 'upload-pack'
> ...
> +SSH Transport
> ...
> +It is basically equivalent to running this:

> +Reference Discovery
> +-------------------
> +
> +When the client initially connects the server will immediately respond
> +with a listing of each reference it has (all branches and tags) along
> +with the object name that each reference currently points to.
> +
> +   $ echo -e -n "0039git-upload-pack
> /schacon/gitbook.git\0host=example.com\0" |

Oops...

> +      nc -v example.com 9418
> +   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack
> thin-pack side-band side-band-64k ofs-delta shallow no-progress
> include-tag

Oops...

It is perfectly fine to fold a long line in the document.  What I
earlier suggested was to state the fact that the document _did_ fold
a long line for typographical reasons and in the actual protocol it
is a single long line to the reader.

> +The returned response is a pkt-line stream describing each ref and
> +its known value.  The stream MUST be sorted by name according to
> +the C locale ordering.

Do we need to say "known"?

> ...
> +  advertised-refs  =  (no-refs / list-of-refs)
> +                      flush-pkt
> +
> +  no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
> +                      NUL capability-list LF)
> +
> +  list-of-refs     =  first-ref *other-ref
> +  first-ref        =  PKT-LINE(obj-id SP refname
> +                      NUL capability-list LF)
> +
> +  other-ref        =  PKT-LINE(other-tip / other-peeled)
> +  other-tip        =  obj-id SP refname LF
> +  other-peeled     =  obj-id SP refname "^{}" LF
> +
> +  capability-list  =  capability *(SP capability)
> +  capability       =  1*(LC_ALPHA / DIGIT / "-" / "_")
> +  LC_ALPHA         =  %x61-7A
> +----
> +
> +Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
> +as case-insensitive.

I hate to sound like a broken parrot, but ...

 - You do not have SHA1 in the above list; say "obj-id".

 - Why is this SHOULD and not MUST?  It's not like you or somebody else
   have already written such a broken server or client and you have to
   grandfather it by defining what goes over the wire looser than the
   current practice.  I think this is taking the "be liberal in what you
   accept" mantra too literally without real reason for doing so.

> +Packfile Negotiation
> +--------------------
> +After reference and capabilities discovery, the client can decide
> +to terminate the connection by sending a flush-pkt, telling the
> +server it can now gracefully terminate (as happens with the ls-remote
> +command) or it can enter the negotiation phase, where the client and
> +server determine what the minimal packfile necessary for transport is.
> +
> +Once the client has the initial list of references that the server
> +has, as well as the list of capabilities, it will begin telling the
> +server what objects it wants and what objects it has, so the server
> +can make a packfile that only has the objects that the client needs.

"only has" -> "only contains", perhaps, as the above has too many has
already?

> +The client will also send a list of the capabilities it supports out
> +of what the server said it could do with the first 'want' line.

It is not _wrong_ per-se, but it is not about client "supporting".  It is
asking these particular protocol extensions enabled.  How about...

	.. will also send a list of the capabilities it wants to be in
        effect, out of ...

> +If the server reads 'have' lines, it then will respond by ACKing any
> +of the obj-ids the client said it had that the server also has. The
> +server will ACK obj-ids differently depending on which ack mode is
> +signaled by the client.

Perhaps "signaled" -> "chosen"?

> +In multi_ack mode:
> ...
> +In multi_ack_detailed mode:
> ...
> +Without multi_ack:
> ...

The last one is "without multi_ack or multi_ack_detailed", isn't it?
I think the order you described these three is sensible (from the most
commonly deployed to merely describing a historical practice).

> +Packfile Data
> +-------------
> +
> +Now that the client and server have done some negotiation about what
> +the minimal amount of data that can be sent to the client is, the server
> +will construct and send the required data in packfile format.

Perhaps "done some" -> "finished"?

Is it "can be sent" or "needs to be sent"?

> +Pushing Data To a Server
> ...
> +references to be complete.  Once all the data is received and validated,
> +the server will then update it's references to what the client specified.

"it's" -> "its".

> +Reference Discovery
> +-------------------
> +
> +The reference discovery phase is done nearly the same way as it is in the
> +fetching protocol. Each reference obj-id and name on the server is sent
> +in packet-line format to the client, followed by a flush packet.  The only

I slightly prefer "a flush packet" spelled out like this, but please be
consistent either way.  You have only two instances of spelled-out "flush
packet" around this section, and everywhere else in this patch you used
"flush-pkt" (I am talking about explanation prose, not ABNF, in which you
consistently used "flush-pkt" everywhere), so changing these "flush
packet" to "flush-pkt" may be easier to change and less error prone.

> +A pack-file MUST be sent if either create or update command is used,
> +even if the server already has all the necessary objects.  In this
> +case the client MUST send an empty pack-file.   The only time this
> +is likely to happen is if the client is doing something like creating
> +a new branch that points to an existing obj-id.

"doing something like" is redundant.

> +The server will receive the packfile, unpack it, then validate each
> +reference that is being updated that it hasn't changed while the request
> +was being processed (the obj-id is still the same as the old-id), and
> +it will run any update hooks to make sure that the update is acceptable.
> +If all of that is fine, the server will then update the references.

Strictly speaking, "unpack it" is a wrong thing to say in a protocol
specification document.  The only requirement is for the server to make
objects in it accessible before the ref update takes place.  The objects
need to be accessible when hooks run.

I was about to suggest "store objects in it in the repository" instead,
but in the status report we do use a successful "unpack" to mean "made
objects accessible successfully", so it probably is Ok as-is.  At least I
cannot think of a better way to rephrase this part.

> +Report Status
> +-------------
> +
> +After receiving the pack data from the sender, the client sends a

"the client sends" -> "the server sends".

Even though it makes me a bit uneasy to describe these entities "server vs
client" (I'd prefer "sender" vs "receiver"), the entire document is
written based on the assumption that "clients" fetch from or push to "the
server", so let's be consistent.

> +report if 'report-status' capability was sent to the server.
> +It is a short listing of what happened in that update.  It will first
> +list the status of the packfile unpacking as either 'unpack ok' or
> +'unpack [error]'.  Then it will list the status for each of the references
> +that it tried to update.  Each line be either 'ok [refname]' if the

Sorry for asking a language question but "be"?

> +An example client/server communication might look like this:
> +
> +----
> +   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d
> refs/heads/local\0report-status delete-refs ofs-delta\n
> +   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
> +   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
> +   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
> +   S: 0000
> +
> +   C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe
> 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
> +   C: 003e74730d410fcb6603ace96f1dc55ea6196122532d
> 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n

Oops.

> diff --git a/Documentation/technical/protocol-capabilities.txt
> b/Documentation/technical/protocol-capabilities.txt
> new file mode 100644
> index 0000000..f4bf986
> --- /dev/null
> +++ b/Documentation/technical/protocol-capabilities.txt
> @@ -0,0 +1,186 @@
> +Git Protocol Capabilities
> +=========================
> +
> +Servers SHOULD support all capabilities defined in this document.
> +
> +On the very first line of the initial server response of either
> +receive-pack and upload-pack the first reference is followed by
> +a null byte and then a list of space delimited server capabilities.

"null" -> "NUL"

> +Client will then send a space separated list of capabilities it
> +can support. The client SHOULD NOT ask for capabilities the server
> +did not say it supports.
> +
> +Server MUST ignore capabilities it does not understand.  Server MUST
> +NOT ignore capabilities that client requested and server advertised.
> +

I hate to sound like a broken parrot, but ...

 - It is more like "Client will ... it wants enabled", not "it can
   support".

 - Is this really "SHOULD NOT", as opposed to "MUST NOT"?  What are
   examples of plausible justifications for client implementations to
   violate this requirement and ask for a capability that it knows the
   server does not support?

 - Shouldn't server "MUST diagnose and abort" connection when client
   requests a protocol feature (i.e. capability) that it does not
   understand?

When the server advertises a capability it itself does not understand
and the client asked for it, then the client can legitimately ask for
it, and the server is not allowed to ignore it, but it must ignore it, so
it cannot satisfy this requirement.  We should spell out that the server
MUST NOT advertise capabilities it does not understand.

> +thin-pack
> +---------
> +
> +This capability implies that the server can send 'thin' packs, packs

Does it imply or explicitly state?  I think it is the latter.

> +which do not contain base objects; if those base objects are available
> +on client side. Client requests 'thin-pack' capability when it
> +understands how to "thicken" them adding required delta bases making
> +them self contained.

A single pack is sent over the wire and thicking it will create a single
pack self contained, hence "making it self contained".

> +Client MUST NOT request 'thin-pack' capability if it cannot turn thin
> +packs into proper independent packs.

"a think pack into a self contained pack"

> +side-band, side-band-64k
> +------------------------
> +
> +This means that server can send, and client understand multiplexed
> +progress reports and error info interleaved with the packfile itself.

Either "This" -> "This capability", or just begin the sentence with
"Server can send..." like your description of "ofs-delta".

> +delete-refs
> +-----------
> +
> +If the server sends back the 'delete-refs' capability, it means that
> +it is capable of accepting an all-zeroed SHA-1 value as the target
> +value of a reference update.  It is not sent back by the client, it
> +simply informs the client that it can be sent zeroed SHA-1 values
> +to delete references.

You earlier called these "all-zeroed SHA-1 value"s "zero-id"s.  Be
consistent.

> diff --git a/Documentation/technical/protocol-common.txt
> b/Documentation/technical/protocol-common.txt
> new file mode 100644
> index 0000000..2dca642
> --- /dev/null
> +++ b/Documentation/technical/protocol-common.txt
> @@ -0,0 +1,96 @@
> ...
> +A refname is a hierarichal octet string beginning with "refs/" and

"hierarchical"

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/2] pack documentation review updates
       [not found]   ` <20091111171924.6117@nanako3.lavabit.com>
@ 2009-11-11 10:05     ` Scott Chacon
  2009-11-15  9:11       ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Scott Chacon @ 2009-11-11 10:05 UTC (permalink / raw)
  To: Nanako Shiraishi
  Cc: Junio C Hamano, Sverre Rabbelier, Shawn O. Pearce, git list

Hey,

On Wed, Nov 11, 2009 at 9:19 AM, Nanako Shiraishi <nanako3@lavabit.com> wrote:
> Update Scott's protocol document according to review comments given by Junio.
>
>  * name of "%00" byte is NUL not null;
>  * requestee sends current values of its refs, not "known values";
>  * consistently use "obj-id";
>  * requestor chooses the capabilities it wants to be in effect;
>  * pack data is sent after negotiation finishes, not just after "some of
>   it is done";
>  * what it has is called "its", not "it's";
>  * consistently use "flush-pkt";
>  * remove redundant "something like";
>  * status report for send-pack is sent from the receiver, not from client;
>  * don't unnecessarily say "SHOULD NOT" when existing servers can satisify
>   "MUST NOT";
>  * only one thin pack is sent and thickened;
>  * an all-zero value is defined as a zero-id, so use it.
>
> Signed-off-by: しらいし ななこ <nanako3@lavabit.com>
> ---

I was _just_ working on this yesterday and had gotten about halfway
through - I'm traveling a lot right now, so I'm a bit behind.  This
looks good, thanks for taking the time Nanako.

Signed-off-by: Scott Chacon <schacon@gmail.com>

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH 2/2] pack documentation review updates
  2009-11-11 10:05     ` [PATCH 2/2] pack documentation review updates Scott Chacon
@ 2009-11-15  9:11       ` Junio C Hamano
  0 siblings, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2009-11-15  9:11 UTC (permalink / raw)
  To: Scott Chacon
  Cc: Nanako Shiraishi, Junio C Hamano, Sverre Rabbelier,
	Shawn O. Pearce, git list

Scott Chacon <schacon@gmail.com> writes:

> On Wed, Nov 11, 2009 at 9:19 AM, Nanako Shiraishi <nanako3@lavabit.com> wrote:
>> Update Scott's protocol document according to review comments given by Junio.
>>
>>  * name of "%00" byte is NUL not null;
>> ...
>>  * don't unnecessarily say "SHOULD NOT" when existing servers can satisify
>>   "MUST NOT";
>> ...
>
> I was _just_ working on this yesterday and had gotten about halfway
> through - I'm traveling a lot right now, so I'm a bit behind.  This
> looks good, thanks for taking the time Nanako.
>
> Signed-off-by: Scott Chacon <schacon@gmail.com>

Thanks, both.

I had some doubts about the "SHOULD NOT"/"MUST" on obj-id myself, but if
you are Ok with the change, I wouldn't complain ;-).

Will squash this in.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  1:18       ` Shawn O. Pearce
@ 2009-11-04  1:48         ` Junio C Hamano
  0 siblings, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2009-11-04  1:48 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Junio C Hamano, Scott Chacon, git list

"Shawn O. Pearce" <spearce@spearce.org> writes:

> Junio C Hamano <gitster@pobox.com> wrote:
>> "Shawn O. Pearce" <spearce@spearce.org> writes:
>> > I don't think we ever send an empty packet.  If we have no data to
>> > send, why the hell did we create the packet header?
>> 
>> Oh, I do not disagree that it is pointless, but the example that followed
>> the part we are discussing also had "0004".  I think it is Ok to allow it.
>
> If its pointless, why encourage it?  Why not discourage it with SHOULD NOT?

Oh, no, I didn't mean to _encourage_ it.

I just thought that it being pointless at the semantic level would already
be an enough discouragement for people who are intelligent enough.

As I said, this was not an objection to start with.

> Sure, but can't packet_write just return early without write()
> if format_packet returned 4 (aka vsnprintf returned 0)?

Ah, that's right.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  1:07     ` Junio C Hamano
@ 2009-11-04  1:18       ` Shawn O. Pearce
  2009-11-04  1:48         ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-04  1:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Scott Chacon, git list

Junio C Hamano <gitster@pobox.com> wrote:
> "Shawn O. Pearce" <spearce@spearce.org> writes:
> > I don't think we ever send an empty packet.  If we have no data to
> > send, why the hell did we create the packet header?
> 
> Oh, I do not disagree that it is pointless, but the example that followed
> the part we are discussing also had "0004".  I think it is Ok to allow it.

If its pointless, why encourage it?  Why not discourage it with SHOULD NOT?
 
> The original intent of packet_flush() was that everything else could be
> kept buffered in-core without going to write() until packet_flush() is
> called.  The protocol was defined in a way that we won't wait for
> listening a response from the other end to an earlier message we "sent"
> with packet_write() but haven't called packet_flush() yet hence could
> still be in our buffer.  We still have this comment:
> 
>     /*
>      * If we buffered things up above (we don't, but we should),
>      * we'd flush it here
>      */
>     void packet_flush(int fd)

The smart-http series causes fetch-pack to buffer.  :-)

> And once we start buffering, allowing "0004" packet_write() wouldn't even
> be a problem; it can be optimized out in the buffering layer.

Sure, but can't packet_write just return early without write()
if format_packet returned 4 (aka vsnprintf returned 0)?

-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  0:56   ` Shawn O. Pearce
@ 2009-11-04  1:07     ` Junio C Hamano
  2009-11-04  1:18       ` Shawn O. Pearce
  0 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-04  1:07 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Scott Chacon, git list

"Shawn O. Pearce" <spearce@spearce.org> writes:

>> > +A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
>> > +is a special case and MUST be handled differently than an empty
>> > +pkt-line ("0004").
>> 
>> ...especially that this sentence makes it sound as if it is perfectly
>> normal to send "0004" for "an empty line" (and I've always thought that is
>> Ok), I am quite puzzled by that "SHOULD NOT".
>
> I don't think we ever send an empty packet.  If we have no data to
> send, why the hell did we create the packet header?

Oh, I do not disagree that it is pointless, but the example that followed
the part we are discussing also had "0004".  I think it is Ok to allow it.

The original intent of packet_flush() was that everything else could be
kept buffered in-core without going to write() until packet_flush() is
called.  The protocol was defined in a way that we won't wait for
listening a response from the other end to an earlier message we "sent"
with packet_write() but haven't called packet_flush() yet hence could
still be in our buffer.  We still have this comment:

    /*
     * If we buffered things up above (we don't, but we should),
     * we'd flush it here
     */
    void packet_flush(int fd)

And once we start buffering, allowing "0004" packet_write() wouldn't even
be a problem; it can be optimized out in the buffering layer.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-04  0:40 ` Junio C Hamano
@ 2009-11-04  0:56   ` Shawn O. Pearce
  2009-11-04  1:07     ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-04  0:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Scott Chacon, git list

Junio C Hamano <gitster@pobox.com> wrote:
> Scott Chacon <schacon@gmail.com> writes:
> 
> > diff --git a/Documentation/technical/protocol-capabilities.txt
> > +
> > +The client MUST send only maximum of one of "side-band" and "side-
> > +band-64k".  Server MUST favor side-band-64k if client requests both.
> 
> Again I think sending both is an error and should be diagnosed as such.
> This is not a three-way handshake where I say "I can handle both", you say
> "I can too", and then I finally pick "then we'll use this one".  There is
> no way for the requesting side to tell which one was chosen, and the
> requester who sent both assumed that the other end chose "side-band" and
> allocated only a 1000-byte buffer like older implementation did, the limit
> of buffer will be busted.

I think Scott borrowed the above from me.  The last sentance with that
server MUST is my error.
 
> Fix the last line "Server MUST favor" to "Server MUST diagnose it as an
> error".  Also drop "A client should ask for only one of them," near the
> beginning of this section, as it is redundant.  I think it is fine to keep
> "A modern client always favors".

Ack, I agree.

> > +include-tag
> > +-----------
> > +
> > +The 'include-tag' capability is about sending tags if we are sending
> > +objects they point to.  If we pack an object to the client, and a tag
> > +points exactly at that object, we pack the tag too.  In general this
> > +allows a client to get all new tags when it fetches a branch, in a
> > +single network connection.
> > +
> > +Clients MAY always send include-tag, hardcoding it into a request.
> 
> "... when the server advertises this capability", no?

This is also my fault.  Its rooted in the way the C implementation
of upload-pack parses the want line, it doesn't care if there are
unrecognized capabilities requested by the client.  This is a bug
in the C implementation.

I agree with you, and disagree with the original text I wrote.
 
> > +Clients SHOULD NOT send include-tag if remote.name.tagopt was set to
> > +--no-tags, as the client doesn't want tag data.
> > +
> > +Servers MUST accept include-tag without error or warning, even if the
> > +server does not understand or support the option.
> 
> Why is this special case here?

Ack, I agree with you, this should be removd.

> > +Servers SHOULD pack the tags if their referrant is packed and the
> > +client has requested include-tag.
> 
> Sorry, I do not understand the motivation to make make this so weak?  If
> the server claims to support this capability, and when a referrant is
> going to the client, the server MUST do so---if it cannot guarantee, why
> claim to support that capability?
> 
> Or am I missing something?

IIRC at one time the C implementation didn't fully ensure the tag is
packed when the referrant is packed.  This SHOULD exists because it
may have been possible for a tag to be omitted.  But I don't think
I've seen this happen under any condition, and it probably is now
a bug if it occurs, which means we likely can convert this to a MUST.
 
> > diff --git a/Documentation/technical/protocol-common.txt
> > +...
> > +pkt-line Format
> > +---------------
> > +
> > +Implementations SHOULD NOT send an empty pkt-line ("0004").
> 
> Not an objection, but where is this coming from?

Me.  I think sending "0004" is stupid.

"0004" must immediately be followed by another pkt-len because there
is no data payload behind it.  "0004" is the same as having called
write(fd, buf, 0), which is equally pointless.  Such a kernel call
will be a no-op, my point here is that "0004" as a packet is also
stupid and shouldn't be sent.
 
> > +A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
> > +is a special case and MUST be handled differently than an empty
> > +pkt-line ("0004").
> 
> ...especially that this sentence makes it sound as if it is perfectly
> normal to send "0004" for "an empty line" (and I've always thought that is
> Ok), I am quite puzzled by that "SHOULD NOT".

I don't think we ever send an empty packet.  If we have no data to
send, why the hell did we create the packet header?

-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-01 23:18 [PATCH] Update packfile transfer protocol documentation Scott Chacon
                   ` (2 preceding siblings ...)
  2009-11-02 23:48 ` Junio C Hamano
@ 2009-11-04  0:40 ` Junio C Hamano
  2009-11-04  0:56   ` Shawn O. Pearce
  3 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-04  0:40 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Shawn O. Pearce

Scott Chacon <schacon@gmail.com> writes:

> diff --git a/Documentation/technical/protocol-capabilities.txt
> b/Documentation/technical/protocol-capabilities.txt
> new file mode 100644
> index 0000000..3c86fc3
> --- /dev/null
> +++ b/Documentation/technical/protocol-capabilities.txt
> @@ -0,0 +1,188 @@
> +Git Protocol Capabilities
> +=========================
> +
> +Servers SHOULD support all capabilities defined in this document.
> +
> +On the very first line of the initial server response, the first
> +reference is followed by a null byte and then a list of space
> +delimited server capabilities.  These allow the server to declare
> +what it can and cannot do to the client.

A few paragraphs below the reader will notice that it talks about both,
but it would be better to make it clear upfront that this document intends
to apply to both of the protocols (fetch-pack protocol and send-pack
protocol).

> +Client sends space separated list of capabilities it wants.  It
> +SHOULD send a subset of server capabilities, i.e do not send
> +capabilities served does not advertise.  The client SHOULD NOT ask
> +for capabilities the server did not say it supports.

The last two sentences are redundant, and "served does not" is probably
"server did not".  I'd suggest dropping from "It SHOULD send a subset"
to "does not advertise."

> +Server MUST ignore capabilities it does not understand.  Server MUST
> +NOT ignore capabilities that client requested and server advertised.

Hmm, is the first sentence true?  Shouldn't it notice and error out?
After all the other end is asking something we do not know how to obey,
and there is no guarantee we do the right thing if we ignore blindly.

> +The 'report-status' and 'delete-refs' capabilities are sent and
> +recognized by the receive-pack (push to server) process.
> +
> +The 'ofs-delta' capability is sent and recognized by both upload-pack
> +and receive-pack protocols.
> +
> +All other capabilities are only recognized by the upload-pack (fetch
> +from server) process.
> +
> +multi_ack
> +---------
> +
> +The 'multi_ack' capability allows the server to return "ACK $SHA1
> +continue" as soon as it finds a commit that it can use as a common
> +base, between the client's wants and the client's have set.

s/$SHA1/obj-id/; to be consistent with the other document.

> +By sending this early, the server can potentially head off the client
> +from walking any further down that particular branch of the client's
> +repository history.  The client may still need to walk down other
> +branches, sending have lines for those, until the server has a
> +complete cut across the DAG, or the client has said "done".
> +
> +Without multi_ack, a client sends have lines in --date-order until
> +the server has found a common base.  That means the client will send
> +have lines that are already known by the server to be common, because
> +they overlap in time with another branch that the server hasn't found
> +a common base on yet.
> +
> +The client has things in caps that the server doesn't; server has
> +things in lower case.

s/things/commits/g; perhaps?

It's a bit abrupt to omit "For example suppose ...; we will illustrate
what happens." entirely.

> +       +---- u ---------------------- x
> +      /             +----- y
> +     /             /
> +    a -- b -- c -- d -- E -- F
> +       \
> +        +--- Q -- R -- S

Is it just my mail client, or is the line from 'd' to 'y' misaligned and
does not begin at 'd'?

> +If the client wants x,y and starts out by saying have F,S, the server
> +doesn't know what F,S is.  Eventually the client says "have d" and
> +the server sends "ACK d continue" to let the client know to stop
> +walking down that line (so don't send c-b-a), but its not done yet,
> +it needs a base for X. The client keeps going with S-R-Q, until a

s/X/x/;

Otherwise, a nice example that is easy to understand.

> +thin-pack
> +---------
> +
> +Server can send thin packs, i.e. packs which do not contain base
> +elements, if those base elements are available on clients side.
> +Client requests thin-pack capability when it understands how to "thicken"
> +them adding required delta bases making them independent.

We call it "base object" when referring to what a "deltified
representation of an object" is based on.  "base element" is a word that
has never been used to describe it elsewhere in our documentation set.

It seems that git-index-pack.txt calls the requirement of a packfile "self
contained and indexable"; I think "self contained" would be a better
wording than "independent" which has never been used to describe this
condition elsewhere in our documentation set.

> +side-band, side-band-64k
> +------------------------
> +
> +This means that server can send, and client understand multiplexed
> +(muxed) progress reports and error info interleaved with the packfile
> +itself.

I don't see need for "(muxed)"; you don't use the abbreviated form
anywhere else in the rest of the document.

> +These two options are mutually exclusive.  A client should ask for
> +only one of them, and a modern client always favors side-band-64k.
> +
> +Either mode indicates that the packfile data will be streamed broken
> +up into packets of either 1000 bytes in the case of 'side_band', or
> +65520 bytes in the case of 'side_band_64k'. Each packet is made up of
> +a leading 4-byte pkt-line length of how much data is in the packet,
> +followed by a 1-byte stream code, followed by the actual data.

I think I mumbled something about "up to" in the other document on this
same topic.  The same comment applies here.

> +The stream code can be one of:
> +
> + 1 - pack data
> + 2 - progress messages
> + 3 - fatal error message just before stream aborts
> +
> +The "side-band-64k" capability came about as a way for newer clients
> +that can handle much larger packets to request packets that are
> +actually crammed nearly full, while maintaining backward compatibility
> +for the older clients.
> +
> +Further, with side-band and its 1000 byte messages, it's actually
> +999 bytes of payload and 1 byte for the stream code. With side-band-64k,
> +same deal, you have 65519 bytes of data and 1 byte for the stream code.
> +
> +The client MUST send only maximum of one of "side-band" and "side-
> +band-64k".  Server MUST favor side-band-64k if client requests both.

Again I think sending both is an error and should be diagnosed as such.
This is not a three-way handshake where I say "I can handle both", you say
"I can too", and then I finally pick "then we'll use this one".  There is
no way for the requesting side to tell which one was chosen, and the
requester who sent both assumed that the other end chose "side-band" and
allocated only a 1000-byte buffer like older implementation did, the limit
of buffer will be busted.

Fix the last line "Server MUST favor" to "Server MUST diagnose it as an
error".  Also drop "A client should ask for only one of them," near the
beginning of this section, as it is redundant.  I think it is fine to keep
"A modern client always favors".

> +ofs-delta
> +---------
> +
> +Server can send, and client understand PACKv2 with delta refering to
> +its base by position in pack rather than by SHA-1.  Its that they can
> +send/read OBJ_OFS_DELTA, aka type 6 in a pack file.

"Its that"?  EPARSE.  Perhaps "That is,"?

> +include-tag
> +-----------
> +
> +The 'include-tag' capability is about sending tags if we are sending
> +objects they point to.  If we pack an object to the client, and a tag
> +points exactly at that object, we pack the tag too.  In general this
> +allows a client to get all new tags when it fetches a branch, in a
> +single network connection.
> +
> +Clients MAY always send include-tag, hardcoding it into a request.

"... when the server advertises this capability", no?

> +The decision for a client to request include-tag only has to do with
> +the client's desires for tag data, whether or not a server had
> +advertised objects in the refs/tags/* namespace.
> +
> +Clients SHOULD NOT send include-tag if remote.name.tagopt was set to
> +--no-tags, as the client doesn't want tag data.
> +
> +Servers MUST accept include-tag without error or warning, even if the
> +server does not understand or support the option.

Why is this special case here?  In the beginning, the servers are required
to support all of these (and include-tag is part of that "all").  If a
server for some justifiable reason does not understand a capability, it
would ignore it anyway with your earlier specification, so there is no
need to spell this out.  Since I do not agree with "ignore capability
requests for something we do not know" at all, I cannot agree with this
sentence.  If a server does not understand this capability, it is an error
for a client to ask for it, and it should be diagnosed as a protocol
error, no?

> +Servers SHOULD pack the tags if their referrant is packed and the
> +client has requested include-tag.

Sorry, I do not understand the motivation to make make this so weak?  If
the server claims to support this capability, and when a referrant is
going to the client, the server MUST do so---if it cannot guarantee, why
claim to support that capability?

Or am I missing something?

> +Clients MUST be prepared for the case where a server has ignored
> +include-tag and has not actually sent tags in the pack.  In such
> +cases the client SHOULD issue a subsequent fetch to acquire the tags
> +that include-tag would have otherwise given the client.
> +
> +The server SHOULD send include-tag, if it supports it, irregardless
> +of whether or not there are tags available.

irregardless?

> diff --git a/Documentation/technical/protocol-common.txt
> b/Documentation/technical/protocol-common.txt
> new file mode 100644
> index 0000000..ddf9912
> --- /dev/null
> +++ b/Documentation/technical/protocol-common.txt
> @@ -0,0 +1,96 @@
> +Documentation Common to Pack and Http Protocols
> +===============================================
> +
> +ABNF Notation
> +-------------
> +
> +ABNF notation as described by RFC 5234 is used within the protocol documents,
> +except the following replacement core rules are used:
> +----
> +  HEXDIG    =  DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
> +----
> +
> +We also define the following common rules:
> +----
> +  NUL       =  %x00
> +  zero-id   =  40*"0"
> +  obj-id    =  40*(HEXDIGIT)
> +
> +  refname  =  "HEAD"
> +  refname /=  "refs/" <see discussion below>
> +----
> +
> +A refname is a hierarichal octet string beginning with "refs/" and
> +not violating the 'git-check-ref-format' command's validation rules.
> +More generally, they:

s/generally/specifically/; I think.  Also if you end with "they:" and
continue with enumeration, each enumerated sentence should omit "they",
no?

> +. They can include slash `/` for hierarchical (directory)
> +  grouping, but no slash-separated component can begin with a
> +  dot `.`.
> +...
> +pkt-line Format
> +---------------
> +
> +Much (but not all) of the payload is described around pkt-lines.
> +
> +A pkt-line is a variable length binary string.  The first four bytes
> +of the line, the pkt-len, indicates the total length of the line,
> +in hexadecimal.  The pkt-len includes the 4 bytes used to contain
> +the length's hexadecimal representation.
> +
> +A pkt-line MAY contain binary data, so implementors MUST ensure
> +pkt-line parsing/formatting routines are 8-bit clean.
> +
> +A non-binary line SHOULD BE terminated by an LF, which if present
> +MUST be included in the total length.
> +
> +The maximum length of a pkt-line's data component is 65520 bytes.
> +Implementations MUST NOT send pkt-line whose length exceeds 65524
> +(65520 bytes of payload + 4 bytes of length data).
> +
> +Implementations SHOULD NOT send an empty pkt-line ("0004").

Not an objection, but where is this coming from?

> +A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
> +is a special case and MUST be handled differently than an empty
> +pkt-line ("0004").

...especially that this sentence makes it sound as if it is perfectly
normal to send "0004" for "an empty line" (and I've always thought that is
Ok), I am quite puzzled by that "SHOULD NOT".

> +----
> +  pkt-line     =  data-pkt / flush-pkt
> +
> +  data-pkt     =  pkt-len pkt-payload
> +  pkt-len      =  4*(HEXDIG)
> +  pkt-payload  =  (pkt-len - 4)*(OCTET)
> +
> +  flush-pkt    = "0000"
> +----
> +
> +Examples (as C-style strings):
> +
> +----
> +  pkt-line          actual value
> +  ---------------------------------
> +  "0006a\n"         "a\n"
> +  "0005a"           "a"
> +  "000bfoobar\n"    "foobar\n"
> +  "0004"            ""

Whew.  Sorry for taking more than a few days to give you review comments.
It must have been quite a lot of work to carefully assemble these
documents.

Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-03 22:05         ` Scott Chacon
@ 2009-11-04  0:40           ` Junio C Hamano
  0 siblings, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2009-11-04  0:40 UTC (permalink / raw)
  To: Scott Chacon; +Cc: Shawn O. Pearce, git list

Scott Chacon <schacon@gmail.com> writes:

> Would you prefer that I try to incorporate all these comments and
> submit another patch, or are you going to modify it in-tree?

I prefer to not munge other people's patches if the modification will
involve more than ten lines and if I know the original submitter can be
trusted to do the right thing.

I would rewrite other's patch myself heavily _only_ after I tried the
usual "suggest to improve" and found that it would not be worth my time to
wait for yet more rounds that would require more suggestions, major part
of which will eventually be forgotten or ignored again, iow, when I sense
that the communication with the contributor is hopelessly inefficient.

Needless to say, you have been here long enough to be in the "trusted"
category.

Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-03  0:58       ` Shawn O. Pearce
@ 2009-11-03 22:05         ` Scott Chacon
  2009-11-04  0:40           ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Scott Chacon @ 2009-11-03 22:05 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Junio C Hamano, git list

Junio,

On Mon, Nov 2, 2009 at 4:58 PM, Shawn O. Pearce <spearce@spearce.org> wrote:
> Junio C Hamano <gitster@pobox.com> wrote:
>> "Shawn O. Pearce" <spearce@spearce.org> writes:
>> > Junio C Hamano <gitster@pobox.com> wrote:
>> > ...
>> >> Shouldn't we say "the client MUST NOT make reference update request if
>> >> everything is up to date" which would imply that in practice there is no
>> >> reason to send an empty pack data?
>
> Creating new branch quirk aside, I do agree with this.  Clients
> shouldn't send no-op updates if it knows in advance the update is
> a no-op.
>
> --
> Shawn.
>

Would you prefer that I try to incorporate all these comments and
submit another patch, or are you going to modify it in-tree?

Thanks,
Scott

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-03  0:36     ` Junio C Hamano
@ 2009-11-03  0:58       ` Shawn O. Pearce
  2009-11-03 22:05         ` Scott Chacon
  0 siblings, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-03  0:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Scott Chacon, git list

Junio C Hamano <gitster@pobox.com> wrote:
> "Shawn O. Pearce" <spearce@spearce.org> writes:
> > Junio C Hamano <gitster@pobox.com> wrote:
> > ...
> >> Shouldn't we say "the client MUST NOT make reference update request if
> >> everything is up to date" which would imply that in practice there is no
> >> reason to send an empty pack data?

Creating new branch quirk aside, I do agree with this.  Clients
shouldn't send no-op updates if it knows in advance the update is
a no-op.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-02 23:57   ` Shawn O. Pearce
@ 2009-11-03  0:36     ` Junio C Hamano
  2009-11-03  0:58       ` Shawn O. Pearce
  0 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-03  0:36 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Scott Chacon, git list

"Shawn O. Pearce" <spearce@spearce.org> writes:

> Junio C Hamano <gitster@pobox.com> wrote:
> ...
>> Shouldn't we say "the client MUST NOT make reference update request if
>> everything is up to date" which would imply that in practice there is no
>> reason to send an empty pack data?
>
> Create a new branch to point at an existing object.  Branch creation
> causes a pack to be expected, but if you are creating a new branch
> that points at an existing object there is nothing to pack.  E.g.:
>
>   git remote add -f A user@host:proj.git
>   git push A A/master:refs/heads/new-branch
>
> causes a 0 object pack file to be sent, assuming the remote project's
> master branch has not changed in between the two commands.

Ahh, you are right.  Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-02 23:48 ` Junio C Hamano
@ 2009-11-02 23:57   ` Shawn O. Pearce
  2009-11-03  0:36     ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-02 23:57 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Scott Chacon, git list

Junio C Hamano <gitster@pobox.com> wrote:
> Scott Chacon <schacon@gmail.com> writes:
> > +
> > +A pack-file MUST be sent if either create or update command is used.
> 
> Easier to read if MUST is followed by "_even_ if", like so:
> 
>     ... MUST be sent when a create or update command is used, even if the
>     server already has all the necessary objects.
> 
> Shouldn't we say "the client MUST NOT make reference update request if
> everything is up to date" which would imply that in practice there is no
> reason to send an empty pack data?

Create a new branch to point at an existing object.  Branch creation
causes a pack to be expected, but if you are creating a new branch
that points at an existing object there is nothing to pack.  E.g.:

  git remote add -f A user@host:proj.git
  git push A A/master:refs/heads/new-branch

causes a 0 object pack file to be sent, assuming the remote project's
master branch has not changed in between the two commands.
 
> > +  pack-file         = "PACK" 24*(OCTET)
> 
> Curious---where does this 24 come from?

Hmmph.  Its wrong actually.  I was trying to write the minimum
number of bytes that make up a pack file, which is actually 28.
(12 in the header minus 4 as "PACK" was already spelled out, plus
20 in the footer for the SHA-1).
 
-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-01 23:18 [PATCH] Update packfile transfer protocol documentation Scott Chacon
  2009-11-02  5:17 ` Junio C Hamano
  2009-11-02 15:43 ` Shawn O. Pearce
@ 2009-11-02 23:48 ` Junio C Hamano
  2009-11-02 23:57   ` Shawn O. Pearce
  2009-11-04  0:40 ` Junio C Hamano
  3 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-02 23:48 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Shawn O. Pearce, Junio C Hamano

Scott Chacon <schacon@gmail.com> writes:

> +Packfile Negotiation
> ...
> +Clients MUST send all the SHAs it wants from the reference

Not "SHAs", but "object names".  It also is Ok to say "obj-ids" as you
are using "obj-id" in the syntax description above (and later paragraphs
in this section).

> +discovery phase as 'want' lines. Clients MUST send at least one
> +'want' command in the request body. Clients MUST NOT mention an
> +obj-id in a 'want' command which did not appear in the response
> +obtained through ref discovery.
> +
> +If client is requesting a shallow clone, it will now send a 'deepen'
> +command with the depth it is requesting.
> +
> +Once all the "want"s (and optional 'deepen') are transferred,
> +clients MUST send a flush. If the client has all the references on
> +the server, client simply flushes and disconnects.

The last sentence is a repetition of the first sentence in this section,
isn't it?

> +TODO: shallow/unshallow response and document the deepen command in the ABNF.
> +
> +Now the client will send a list of the obj-ids it has.  In multi_ack

Need to say something like 'using "have" lines'.

> +mode, the canonical implementation will send up to 32 of these at a
> +time, then will send a flush-pkt.  The canonical implementation will
> +also skip ahead and send the next 32 immediately, so that there is
> +always a block of 32 "in-flight on the wire" at a time.

I'm a bit lost with this "will also".  Is it describing what happens
without multi-ack?  That is, "with multi-ack, 32 haves are sent ahead, and
this is also done without multi-ack" (which I think is correct, but is a
confusing way to say it)?

> +If the client has no objects (as in the case of a non-referencing
> +clone), it will skip this phase, just send it's 'done' and wait for
> +the packfile.

Hmm, it logically follows that it will say 'done' without any list of
have, if the downloader is in an empty repository.  Are these three lines
worth having?

> +A simple clone may look like this (with no 'have' statements):

The document uses three words (statement, command, line) to refer to the
same thing --- I think we should just pick and stick to one.  I think
existing documents say "want line", "have line", but I didn't count.

> +----
> +   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
> +     side-band-64k ofs-delta\n
> +   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
> +   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
> +   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
> +   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
> +   C: 0000
> +   C: 0009done\n
> +
> +   S: 0008NAK\n
> +   S: [PACKFILE]
> +----
> +
> +An incremental update (fetch) response might look like this:
> +
> +----
> +   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
> +     side-band-64k ofs-delta\n
> +   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
> +   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
> +   C: 0000
> +   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
> +   C: [30 more have lines]
> +   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
> +   C: 0000
> +
> +   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
> +   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
> +   S: 0008NAK\n
> +
> +   C: 0009done\n
> +
> +   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
> +   S: [PACKFILE]
> +----

Nice.

> +Packfile Data
> +-------------
> +
> +Now that the client and server have done some negotiation about what
> +the minimal amount of data that can be sent to the client is, the server
> +will construct and send the required data in packfile format.
> +
> +See pack-format.txt for what the packfile itself actually looks like.
> +
> +If 'side-band' or 'side-band-64k' capabilities have been specified by
> +the client, the server will send the packfile data multiplexed.
> +
> +Each packet starting with the packet-line length of the amount of data
> +that follows, followed by a single byte specifying the sideband the
> +following data is coming in on.
> +
> +In 'side-band' mode, it will send 999 data bytes plus 1 control code,
> +for a total of 1000 bytes in a pkt-line.  In 'side-band-64k' mode it
> +will send 65519 data bytes plus 1 control code, for a total of 65520
> +bytes in a pkt-line.

It would need to say "up to 999" (and "up to 65519").

> +The sideband byte will be either a '1' or a '2'. Sideband '1' will contain
> +packfile data, sideband '2' will be used for progress information that the
> +client will generally print to stderr.

Band '3' is used for emergency abort, isn't it?

> +Pushing Data To a Server
> +========================
> +
> +Pushing data to a server will invoke the 'receive-pack' process on the
> +server, which will allow the client to tell it which references it should
> +update and then send all the data the server will need for those new
> +references to be complete.  Once all the data is received and validated,
> +the server will then update it's references to what the client specified.
> +
> +Authentication
> +--------------
> +
> +The protocol itself contains no authentication mechanisms.  That is to be
> +handled by the transport, such as SSH, before the 'receive-pack' process is
> +invoked.  If 'receive-pack' is configured over the Git transport, those
> +repositories will be writable by anyone who can access that port (9418) as
> +that transport is unauthenticated.
> +
> +Reference Discovery
> +-------------------
> +
> +The reference discovery phase is done nearly the same way as it is in the
> +fetching protocol. Each reference obj-id and name on the server is sent
> +in packet-line format to the client, followed by a flush packet.  The only
> +real difference is that the capability listing is different - the only
> +possible values are 'report-status', 'delete-refs' and 'ofs-delta'.

We should describe what should happen when there are new capabiliities
advertised by the other side that we do not understand (we ignore, and do
not barf).  Even though I forgot to comment on the fetch side, there is
the same issue over there.

If the receiving end does not support delete-refs, the sending end MUST
NOT ask for delete command.

> +Reference Update Request and Packfile Transfer
> +----------------------------------------------
> +
> +Once the client knows what references the server is at, it can send a
> +list of reference update requests.  For each reference on the server
> +that it wants to update, it sends a line listing the obj-id currently on
> +the server, the obj-id the client would like to update it to and the name
> +of the reference.
> +
> +This list is followed by a flush packet and then the packfile that should
> +contain all the objects that the server will need to complete the new
> +references.
> +
> +The pack-file MUST NOT be sent if the only command used is 'delete'.
> +
> +A pack-file MUST be sent if either create or update command is used.
> +An empty pack-file MUST be sent if a create or update command is
> +used, and the server already obviously has the object (e.g. the
> +SHA-1 is already pointed to by another ref that was listed in the
> +advertisement).

Easier to read if MUST is followed by "_even_ if", like so:

    ... MUST be sent when a create or update command is used, even if the
    server already has all the necessary objects.

Shouldn't we say "the client MUST NOT make reference update request if
everything is up to date" which would imply that in practice there is no
reason to send an empty pack data?

> +----
> +  update-request    =  command-list [pack-file]
> +
> +  command-list      =  PKT-LINE(command NUL capability-list LF)
> +                       *PKT-LINE(command LF)
> +                       flush-pkt
> +
> +  command           =  create / delete / update
> +  create            =  zero-id SP new-id  SP name
> +  delete            =  old-id  SP zero-id SP name
> +  update            =  old-id  SP new-id  SP name
> +
> +  old-id            =  obj-id
> +  new-id            =  obj-id
> +
> +  pack-file         = "PACK" 24*(OCTET)

Curious---where does this 24 come from?

> +----
> +
> +The server will receive the packfile, unpack it, then validate each
> +reference that is being updated that it hasn't changed while the request
> +was being processed (the obj-id is still the same as the old-id), and
> +it will run any update hooks to make sure that the update is acceptable.
> +If all of that is fine, the server will then update the references.

Nice.

> +Report Status
> +-------------
> +
> +If the 'report-status' capability is sent by the client, then the server
> +will send a short report of what happened in that update.  It will first
> +list the status of the packfile unpacking as either 'unpack ok' or
> +'unpack [error]'.  Then it will list the status for each of the references
> +that it tried to update.  Each line be either 'ok [refname]' if the
> +update was successful, or 'ng [refname] [error]' if the update was not.

Unlike previous sections, this section does not begin with "after the
above is done, this happens", so it is not clear where in the protocol
exchange this report is done.  Presumably, you meant "After receiving the
pack data from the sender, the receiver sends a report if report-status
was asked previously"?

> +----
> +  report-status     = unpack-status
> +                      1*(command-status)
> +                      flush-pkt
> +
> +  unpack-status     = PKT-LINE("unpack" SP unpack-result LF)
> +  unpack-result     = "ok" / error-msg
> +
> +  command-status    = command-ok / command-fail
> +  command-ok        = PKT-LINE("ok" SP refname LF)
> +  command-fail      = PKT-LINE("ng" SP refname SP error-msg LF)
> +
> +  error-msg         = 1*(OCTECT) ; where not "ok"
> +----
> +
> +Updates can be unsuccessful for a number of reasons.  The reference can have
> +changed since the reference discovery phase was originally sent, meaning
> +someone pushed in the meantime.  The reference being pushed could be a
> +non-fast-forward reference and the update hooks or configuration could be
> +set to not allow that, etc.  Also, some references can be updated while others
> +can be rejected.

Nice.

> +An example client/server communication might look like this:
> +
> +----
> +   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d
> refs/heads/local\0report-status delete-refs ofs-delta\n
> +   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
> +   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
> +   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
> +   S: 0000
> +
> +   C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe
> 74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
> +   C: 003e74730d410fcb6603ace96f1dc55ea6196122532d
> 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
> +   C: 0000
> +   C: [PACKDATA]
> +
> +   S: 000aunpack ok\n
> +   S: 0014ok refs/heads/debug\n
> +   S: 0026ng refs/heads/master non-fast-forward\n

Thanks; my review on the remainder will be in a (yet another) separate
message.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-02 15:41   ` Shawn O. Pearce
@ 2009-11-02 17:31     ` Junio C Hamano
  0 siblings, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2009-11-02 17:31 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Scott Chacon, git list

"Shawn O. Pearce" <spearce@spearce.org> writes:

> If its SHA-1 you are talking about, I wanted this to be a MUST
> use lowercase, but people screamed about it (Jakub and Ilari
> IIRC).  The current C code accepts uppercase due to its use of
> get_sha1_hex(), and they wanted to follow the "be liberal in what
> you accept" suggestion from other IETF authors.
>
> IIRC, all implementations use lowercase.  We should be able to safely
> say MUST produce lowercase, and MUST accept lowercase, and SHOULD
> NOT accept uppercase,...

I do not see a point in loosening or tightening the definition
document that is written to describe a protocol of a reference
implementation after the fact.  It is not like producing lowercase
hexdegits is a lot more work on some weird platforms.

Everybody writes in lowercase, expects to see lowercase, and some may
accept uppercase by accident.  I think it is acceptable to describe that
as "MUST produce, MUST accept lc and MAY accept uc", but I do not think it
is even necessary to specifically say "and MAY accept uc".

It is actively wrong to say "SHOULD NOT accept uc"---it won't help
anybody.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-01 23:18 [PATCH] Update packfile transfer protocol documentation Scott Chacon
  2009-11-02  5:17 ` Junio C Hamano
@ 2009-11-02 15:43 ` Shawn O. Pearce
  2009-11-02 23:48 ` Junio C Hamano
  2009-11-04  0:40 ` Junio C Hamano
  3 siblings, 0 replies; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-02 15:43 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Junio C Hamano

Scott Chacon <schacon@gmail.com> wrote:
> I've incorporated the comments from Shawn (except for the 'annotated
> tag' comment
> in the 'include-tag' section of the capabilities doc, which I didn't
> understand).
...
> +include-tag
> +-----------
> +
> +The 'include-tag' capability is about sending tags if we are sending
> +objects they point to.  If we pack an object to the client, and a tag
> +points exactly at that object, we pack the tag too.  In general this
> +allows a client to get all new tags when it fetches a branch, in a
> +single network connection.

There are two types of tags, annotated and lightweight, right?

To avoid confusion here we should make it clear we only send
annotated tag objects when this feature is enabled.  The protocol
doesn't have provisions to send SHA-1 to ref mapping inside of a
pack stream, so lightweight tags cannot be sent.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-02  5:17 ` Junio C Hamano
@ 2009-11-02 15:41   ` Shawn O. Pearce
  2009-11-02 17:31     ` Junio C Hamano
  0 siblings, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-11-02 15:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Scott Chacon, git list

Junio C Hamano <gitster@pobox.com> wrote:
> Scott Chacon <schacon@gmail.com> writes:
> > +Git Protocol
> > +------------
> > +
> > +The Git protocol starts off by sending "git-receive-pack 'repo.git'"
> > +on the wire using the pkt-line format, followed by a null byte and a
> > +hostname paramater, terminated by a null byte.
> > +
> > +   0032git-upload-pack /project.git\0host=myserver.com\0
> 
>  - The example and the first line of the description contradict with each
>    other.

Yes.  The first line description implies the repository path is
wrapped in single quotes, but the example doesn't, because the
protocol doesn't.
 
> > +Initiating the upload-pack or receive-pack processes over SSH is
...
> 
> This depends on the intended audience of this document, but if we are
> writing for people who want to implement their own gitosis and gitolite to
> replace the login shell spawned by ssh daemon,

We are.  If we aren't, we should be.  This is an area everyone has
struggled with.  I had to fight with GitHub to get them to properly
support ssh:// style URLs and not just the scp-style URL.

> you may want to explain the
> "command line" given to it a bit more precisely.  Specifically:
> 
>  - The "command name" is spelled with dash (e.g. git-upload-pack), but
>    this can be overridden by the client;
> 
>  - The repository path is always quoted with sq (i.e. by sq_quote_buf()).

One thing I have been confused on is how ~user is handled here,
because it seems to me we would be allowing ~user outside of the
sq path, so the shell can expand ~user to /home/user or whatever.
But the C code reads to me like we don't do that.
 
> > +Reference Discovery
> > +-------------------
...
> > +   00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
> > +   003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
> > +   003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
> > +   003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
> > +   003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
> > +   0000
> > +Server SHOULD terminate each non-flush line
> > +using LF ("\n") terminator; client MUST NOT complain if there is no
> > +terminator.
> 
> Hmm, LF ("\n") makes me wonder how precise we would want to be.  We
> probably should also say we use ASCII (meaning "not EBCDIC") somewhere but
> that level of details can wait until a more later draft..

True.  But the common document which also explains our ABNF includes
a definition of LF as the byte %x0D.  It might be sufficient to
also say we mean ASCII in that document, though I think these days
that's implied when you start using the IETF ABNF grammar for a
network protocol.  Nobody in their right mind assumes EBCDIC.

> > +The returned response is a pkt-line stream describing each ref and
> > +its known value.  The stream SHOULD be sorted by name according to
> > +the C locale ordering.  The stream SHOULD include the default ref
> > +named 'HEAD' as the first ref.  The stream MUST include capability
> > +declarations behind a NUL on the first ref.
> 
> I have a vague recollection that in a recent discussion (not discussion on
> this documentation patch, but on a "builtin-fetch.c" patch around mid
> September), we decided that the above two SHOULD should be MUST.  Another
> MUST that is missing from here is that a line that describes a peeled tag
> MUST immediately follow the tag itself.

Almost, yes.

The first SHOULD about sorting is a MUST.

Another MUST missing here is that the peeled value of a ref (that is
"ref^{}") MUST be immediately after the ref itself, if presented.
A conforming server MUST peel the ref if its an annotated tag.

The second SHOULD regarding HEAD is more delicate to word.  I think
its more like:

  If HEAD is a valid ref, HEAD MUST appear as the first advertised
  ref.  If HEAD is not a valid ref, HEAD MUST NOT appear in the
  advertisement list at all, but other refs may still appear.

Consider what happens when HEAD is a symref to refs/heads/foo, but
that branch doesn't exist yet, but refs/heads/master does exist.
The repository is completely valid (it'll pass fsck --full), HEAD
won't advertise, but master will.  A clone will fail with no HEAD
reference, but that doesn't mean you can't pull from it with a more
specific refspec.

We shouldn't encourage repository owners to setup their repository
with a dangling HEAD like that, but this is the wrong document to
explain that in.

> > +	capability-list  =  capability *(SP capability)
> > +    capability       =  1*(ALPHA / DIGIT / "-" / "_")
> > +----
> > +
> > +Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
> > +as case-insensitive.
> 
> Why do we need to retroactively loosen these to allow uppercases?  Are
> there implementations that want this loosening?

Are you talking about capabilities?  That was a mistake in my draft.
This should instead be:

  capability       =  1*(LC_ALPHA / DIGIT / "-" / "_")
  LC_ALPHA         =  %x61-7A


If its SHA-1 you are talking about, I wanted this to be a MUST
use lowercase, but people screamed about it (Jakub and Ilari
IIRC).  The current C code accepts uppercase due to its use of
get_sha1_hex(), and they wanted to follow the "be liberal in what
you accept" suggestion from other IETF authors.

IIRC, all implementations use lowercase.  We should be able to safely
say MUST produce lowercase, and MUST accept lowercase, and SHOULD
NOT accept uppercase, but then the canonical C implementation isn't
exactly conforming anymore due to get_sha1_hex().  Hell, pkt-line.c
also wouldn't conform I guess, it will read uppercase hex.
 
-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-11-01 23:18 [PATCH] Update packfile transfer protocol documentation Scott Chacon
@ 2009-11-02  5:17 ` Junio C Hamano
  2009-11-02 15:41   ` Shawn O. Pearce
  2009-11-02 15:43 ` Shawn O. Pearce
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 25+ messages in thread
From: Junio C Hamano @ 2009-11-02  5:17 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Shawn O. Pearce, Junio C Hamano

Scott Chacon <schacon@gmail.com> writes:

> The technical documentation for the packfile protocol is both sparse and
> incorrect.  This documents the fetch-pack/upload-pack and send-pack/
> receive-pack protocols much more fully.
>
> Add documentation from Shawn's upcoming http-protocol docs that is shared
> by the packfile protocol. protocol-common.txt describes ABNF notation
> amendments, refname rules and the packet line format.
>
> Add documentation on the various capabilities supported by the
> upload-pack and receive-pack protocols. protocol-capabilities.txt describes
> multi-ack, thin-pack, side-band[-64k], shallow, no-progress, include-tag,
> ofs-delta, delete-refs and report-status.
>
> Signed-Off-By: Scott Chacon <schacon@gmail.com>
> ---

This is just for future reference, but please downcase O and B above.

> diff --git a/Documentation/technical/pack-protocol.txt
> b/Documentation/technical/pack-protocol.txt
> index 9cd48b4..1cc61d8 100644
> --- a/Documentation/technical/pack-protocol.txt
> +++ b/Documentation/technical/pack-protocol.txt
> +Packfile transfer protocols
> +===========================
> +
> +Git supports transferring data in packfiles over the ssh://, git:// and
> +file:// transports.  There exist two sets of protocols, one for pushing
> +data from a client to a server and another for fetching data from a
> +server to a client.  All three transports (ssh, git, file) use the same
> +protocol to transfer data.
> +
> +The processes invoked in the canonical Git implementation are 'upload-pack'
> +on the server side and 'fetch-pack' on the client side for fetching data;
> +then 'receive-pack' on the server and 'send-pack' on the client for pushing
> +data.  The protocol functions to have a server tell a client what is
> +currently on the server, then for the two to negotiate the smallest amount
> +of data to send in order to fully update one or the other.
> +
> +Transports
> +----------
> +There are three transports over which the packfile protocol is
> +initiated.  The Git transport is a simple, unauthenticated server that
> +simply takes the command (almost always 'upload-pack', though Git
> +servers can be configured to be globally writable, in which 'receive-
> +pack' initiation is also allowed) with which the client wishes to
> +communicate and executes it and connects it to the requesting
> +process.
> +
> +In the SSH transport, the client basically just runs the 'upload-pack'
> +or 'receive-pack' process on the server over the SSH protocol and then
> +communicates with that invoked process over the SSH connection.
> +
> +The file:// transport simply runs the 'upload-pack' or 'receive-pack'
> +process locally and communicates with it over a pipe.

Very nicely and concisely written.  Noise words like "simply" and
"basically" might be better omitted, though (not just this part but in the
rest of the document as well).

Yes, I admit I have the tendency to excessively use them, too.

> +Git Protocol
> +------------
> +
> +The Git protocol starts off by sending "git-receive-pack 'repo.git'"
> +on the wire using the pkt-line format, followed by a null byte and a
> +hostname paramater, terminated by a null byte.
> +
> +   0032git-upload-pack /project.git\0host=myserver.com\0

Two-and-a-half issues.

 - You are calling distinction between ssh/git/file "transport", and the
   actual data exchange for pushing/fetching "protocol" in the first part
   of the document, and I agree with the choice of words.  The header for
   this section should read "Git Transport", as that is what you are
   describing.

 - The example and the first line of the description contradict with each
   other.

 - As you already said that receive-pack could be requested over git
   transport in the earlier part, I would fix the description on the first
   line to say "... by sending 'command' and 'repository' on the wire ..."
   to make it explain the _concept_.

> +--
> +   git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
> +   request-command   = "git-upload-pack" / "git-receive-pack" /
> +                       "git-upload-archive"   ; case sensitive
> +   pathname          = *( %x01-ff ) ; exclude NUL
> +   host-parameter    = "host=" hostname [ ":" port ]
> +--
> +Only host-parameter is allowed in the git-proto-request. Clients
> +MUST NOT attempt to send additional parameters. It is used for the
> +git-daemon name based virtual hosting.  See --interpolated-path
> +option to git daemon, with the %H/%CH format characters.
> +Basically what the Git client is doing to connect to an 'upload-pack'
> +process on the server side over the Git protocol is this:
> +
> +   $ echo -e -n \
> +     "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
> +     nc -v example.com 9418
> +
> +
> +SSH Protocol
> +------------

This is "SSH Transport", I think.

> +Initiating the upload-pack or receive-pack processes over SSH is
> +simply executing the binary on the server via SSH remote execution.
> +It is basically equivalent to running this:
> +
> +   $ ssh git.example.com "git-upload-pack '/project.git'"
> +
> +For a server to support Git pushing and pulling for a given user over
> +SSH, that user needs to be able to execute one or both of those
> +commands via the SSH shell that they are provided on login.  On some
> +systems, that shell access is limited to only being able to run those
> +two commands, or even just one of them.
> +
> +In an ssh:// format URI, it's absolute in the URI, so the '/' after
> +the host name (or port number) is sent as an argument, which is then
> +read by the remote git-upload-pack exactly as is, so it's effectively
> +an absolute path in the remote filesystem.
> +
> +       git clone ssh://user@example.com/project.git
> +                    |
> +                    v
> +    ssh user@example.com "git-upload-pack '/project.git'"
> +
> +In a "user@host:path" format URI, its relative to the user's home
> +directory, because the Git client will run:
> +
> +     git clone user@example.com:project.git
> +                    |
> +                    v
> +  ssh user@example.com "git-upload-pack 'project.git'"
> +
> +The exception is if a '~' is used, in which case
> +we execute it without the leading '/'.
> +
> +      ssh://user@example.com/~alice/project.git,
> +                     |
> +                     v
> +   ssh user@example.com "git-upload-pack '~alice/project.git'"

This depends on the intended audience of this document, but if we are
writing for people who want to implement their own gitosis and gitolite to
replace the login shell spawned by ssh daemon, you may want to explain the
"command line" given to it a bit more precisely.  Specifically:

 - The "command name" is spelled with dash (e.g. git-upload-pack), but
   this can be overridden by the client;

 - The repository path is always quoted with sq (i.e. by sq_quote_buf()).

> +Fetching Data From a Server
> +===========================
> +
> +When one Git repository wants to get all the data that a second
> +repository has, the first can 'fetch' from the second.  This
> +operation determines what data the server has that the client does
> +not then streams that data down to the client in packfile format.

I've been disturbed by this "all" since your first draft, as fetching data
reachable from only a few refs but not all is perfectly a valid thing to
do, but I am not sure if it is worth complicating this document to clarify
this point.  Probably not---but then the above would read perfectly well
without "all".

> +The server side binaries need to be executable as 'git-upload-pack'
> +for fetching and 'git-receive-pack' for pushing over SSH, since the
> +Git clients will connect to the server and attempt to run that command
> +directly.  Over the Git protocol, one could write their own daemon
> +that sees that the client is trying to invoke those commands and
> +simply handle the requests.

I am not sure what audience this paragraph is trying to help by making it
sound as if git transport allows customized daemon but ssh transport
doesn't.  gitosis and gitolite are examples of "own daemon that sees that
the client is trying to invoke those commands and simply handle the
requests" over SSH, aren't they?  So if the purpose is to help server
authors, this paragraph does more harm than being useful.  If the purpose
is to satisfy curiosity, I doubt this level of detail is necessary.

Also there is a terminology mix-up; the last sentence should begin with
"Over the Git transport".

> +Reference Discovery
> +-------------------
> +
> +When the client initially connects the server will immediately respond
> +with a listing of each reference it has (all branches and tags) along
> +with the commit SHA that each reference currently points to.

Not "the commit SHA", but "object name". a ref can point at a non-commit
object, such as a tag.

> +   $ echo -e -n \
> +     "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
> +      nc -v example.com 9418
> +   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack \
> +     thin-pack side-band side-band-64k ofs-delta shallow no-progress \
> +     include-tag

We should explain this is actually a long single line, and line folding
with backslashes is solely for the readers of this document, after this
sample response.

> +   00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
> +   003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
> +   003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
> +   003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
> +   003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
> +   0000
> +Server SHOULD terminate each non-flush line
> +using LF ("\n") terminator; client MUST NOT complain if there is no
> +terminator.

Hmm, LF ("\n") makes me wonder how precise we would want to be.  We
probably should also say we use ASCII (meaning "not EBCDIC") somewhere but
that level of details can wait until a more later draft..

> +The returned response is a pkt-line stream describing each ref and
> +its known value.  The stream SHOULD be sorted by name according to
> +the C locale ordering.  The stream SHOULD include the default ref
> +named 'HEAD' as the first ref.  The stream MUST include capability
> +declarations behind a NUL on the first ref.

I have a vague recollection that in a recent discussion (not discussion on
this documentation patch, but on a "builtin-fetch.c" patch around mid
September), we decided that the above two SHOULD should be MUST.  Another
MUST that is missing from here is that a line that describes a peeled tag
MUST immediately follow the tag itself.

Shawn?

> +----
> +	advertised-refs  =  (no-refs / list-of-refs)
> +			    flush-pkt
> +
> +	no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
> +				     NUL capability-list LF)
> +
> +	list-of-refs     =  first-ref *other-ref
> +	first-ref        =  PKT-LINE(obj-id SP refname
> +				     NUL capability-list LF)
> +
> +	other-ref        =  PKT-LINE(other-tip / other-peeled)
> +	other-tip        =  obj-id SP refname LF
> +	other-peeled     =  obj-id SP refname "^{}" LF
> +
> +	capability-list  =  capability *(SP capability)
> +    capability       =  1*(ALPHA / DIGIT / "-" / "_")
> +----
> +
> +Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
> +as case-insensitive.

Why do we need to retroactively loosen these to allow uppercases?  Are
there implementations that want this loosening?

> +Packfile Negotiation
> +--------------------

I'll look at the rest another day.

Thanks.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] Update packfile transfer protocol documentation
@ 2009-11-01 23:18 Scott Chacon
  2009-11-02  5:17 ` Junio C Hamano
                   ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Scott Chacon @ 2009-11-01 23:18 UTC (permalink / raw)
  To: git list; +Cc: Shawn O. Pearce, Junio C Hamano

The technical documentation for the packfile protocol is both sparse and
incorrect.  This documents the fetch-pack/upload-pack and send-pack/
receive-pack protocols much more fully.

Add documentation from Shawn's upcoming http-protocol docs that is shared
by the packfile protocol. protocol-common.txt describes ABNF notation
amendments, refname rules and the packet line format.

Add documentation on the various capabilities supported by the
upload-pack and receive-pack protocols. protocol-capabilities.txt describes
multi-ack, thin-pack, side-band[-64k], shallow, no-progress, include-tag,
ofs-delta, delete-refs and report-status.

Signed-Off-By: Scott Chacon <schacon@gmail.com>
---

I've incorporated the comments from Shawn (except for the 'annotated
tag' comment
in the 'include-tag' section of the capabilities doc, which I didn't
understand).  I also
fixed the whitespace issues that were in most of the ABNF sections.

 Documentation/technical/pack-protocol.txt         |  529 +++++++++++++++++++--
 Documentation/technical/protocol-capabilities.txt |  188 ++++++++
 Documentation/technical/protocol-common.txt       |   96 ++++
 3 files changed, 772 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/technical/protocol-capabilities.txt
 create mode 100644 Documentation/technical/protocol-common.txt

diff --git a/Documentation/technical/pack-protocol.txt
b/Documentation/technical/pack-protocol.txt
index 9cd48b4..1cc61d8 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -1,41 +1,488 @@
-Pack transfer protocols
-=======================
-
-There are two Pack push-pull protocols.
-
-upload-pack (S) | fetch/clone-pack (C) protocol:
-
-	# Tell the puller what commits we have and what their names are
-	S: SHA1 name
-	S: ...
-	S: SHA1 name
-	S: # flush -- it's your turn
-	# Tell the pusher what commits we want, and what we have
-	C: want name
-	C: ..
-	C: want name
-	C: have SHA1
-	C: have SHA1
-	C: ...
-	C: # flush -- occasionally ask "had enough?"
-	S: NAK
-	C: have SHA1
-	C: ...
-	C: have SHA1
-	S: ACK
-	C: done
-	S: XXXXXXX -- packfile contents.
-
-send-pack | receive-pack protocol.
-
-	# Tell the pusher what commits we have and what their names are
-	C: SHA1 name
-	C: ...
-	C: SHA1 name
-	C: # flush -- it's your turn
-	# Tell the puller what the pusher has
-	S: old-SHA1 new-SHA1 name
-	S: old-SHA1 new-SHA1 name
-	S: ...
-	S: # flush -- done with the list
-	S: XXXXXXX --- packfile contents.
+Packfile transfer protocols
+===========================
+
+Git supports transferring data in packfiles over the ssh://, git:// and
+file:// transports.  There exist two sets of protocols, one for pushing
+data from a client to a server and another for fetching data from a
+server to a client.  All three transports (ssh, git, file) use the same
+protocol to transfer data.
+
+The processes invoked in the canonical Git implementation are 'upload-pack'
+on the server side and 'fetch-pack' on the client side for fetching data;
+then 'receive-pack' on the server and 'send-pack' on the client for pushing
+data.  The protocol functions to have a server tell a client what is
+currently on the server, then for the two to negotiate the smallest amount
+of data to send in order to fully update one or the other.
+
+Transports
+----------
+There are three transports over which the packfile protocol is
+initiated.  The Git transport is a simple, unauthenticated server that
+simply takes the command (almost always 'upload-pack', though Git
+servers can be configured to be globally writable, in which 'receive-
+pack' initiation is also allowed) with which the client wishes to
+communicate and executes it and connects it to the requesting
+process.
+
+In the SSH transport, the client basically just runs the 'upload-pack'
+or 'receive-pack' process on the server over the SSH protocol and then
+communicates with that invoked process over the SSH connection.
+
+The file:// transport simply runs the 'upload-pack' or 'receive-pack'
+process locally and communicates with it over a pipe.
+
+Git Protocol
+------------
+
+The Git protocol starts off by sending "git-receive-pack 'repo.git'"
+on the wire using the pkt-line format, followed by a null byte and a
+hostname paramater, terminated by a null byte.
+
+   0032git-upload-pack /project.git\0host=myserver.com\0
+
+--
+   git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
+   request-command   = "git-upload-pack" / "git-receive-pack" /
+                       "git-upload-archive"   ; case sensitive
+   pathname          = *( %x01-ff ) ; exclude NUL
+   host-parameter    = "host=" hostname [ ":" port ]
+--
+
+Only host-parameter is allowed in the git-proto-request. Clients
+MUST NOT attempt to send additional parameters. It is used for the
+git-daemon name based virtual hosting.  See --interpolated-path
+option to git daemon, with the %H/%CH format characters.
+
+Basically what the Git client is doing to connect to an 'upload-pack'
+process on the server side over the Git protocol is this:
+
+   $ echo -e -n \
+     "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+     nc -v example.com 9418
+
+
+SSH Protocol
+------------
+
+Initiating the upload-pack or receive-pack processes over SSH is
+simply executing the binary on the server via SSH remote execution.
+It is basically equivalent to running this:
+
+   $ ssh git.example.com "git-upload-pack '/project.git'"
+
+For a server to support Git pushing and pulling for a given user over
+SSH, that user needs to be able to execute one or both of those
+commands via the SSH shell that they are provided on login.  On some
+systems, that shell access is limited to only being able to run those
+two commands, or even just one of them.
+
+In an ssh:// format URI, it's absolute in the URI, so the '/' after
+the host name (or port number) is sent as an argument, which is then
+read by the remote git-upload-pack exactly as is, so it's effectively
+an absolute path in the remote filesystem.
+
+       git clone ssh://user@example.com/project.git
+                    |
+                    v
+    ssh user@example.com "git-upload-pack '/project.git'"
+
+In a "user@host:path" format URI, its relative to the user's home
+directory, because the Git client will run:
+
+     git clone user@example.com:project.git
+                    |
+                    v
+  ssh user@example.com "git-upload-pack 'project.git'"
+
+The exception is if a '~' is used, in which case
+we execute it without the leading '/'.
+
+      ssh://user@example.com/~alice/project.git,
+                     |
+                     v
+   ssh user@example.com "git-upload-pack '~alice/project.git'"
+
+Fetching Data From a Server
+===========================
+
+When one Git repository wants to get all the data that a second
+repository has, the first can 'fetch' from the second.  This
+operation determines what data the server has that the client does
+not then streams that data down to the client in packfile format.
+
+The server side binaries need to be executable as 'git-upload-pack'
+for fetching and 'git-receive-pack' for pushing over SSH, since the
+Git clients will connect to the server and attempt to run that command
+directly.  Over the Git protocol, one could write their own daemon
+that sees that the client is trying to invoke those commands and
+simply handle the requests.
+
+
+Reference Discovery
+-------------------
+
+When the client initially connects the server will immediately respond
+with a listing of each reference it has (all branches and tags) along
+with the commit SHA that each reference currently points to.
+
+   $ echo -e -n \
+     "0039git-upload-pack /schacon/gitbook.git\0host=example.com\0" |
+      nc -v example.com 9418
+   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack \
+     thin-pack side-band side-band-64k ofs-delta shallow no-progress \
+     include-tag
+   00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
+   003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
+   003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
+   003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
+   003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
+   0000
+
+Server SHOULD terminate each non-flush line
+using LF ("\n") terminator; client MUST NOT complain if there is no
+terminator.
+
+The returned response is a pkt-line stream describing each ref and
+its known value.  The stream SHOULD be sorted by name according to
+the C locale ordering.  The stream SHOULD include the default ref
+named 'HEAD' as the first ref.  The stream MUST include capability
+declarations behind a NUL on the first ref.
+
+----
+	advertised-refs  =  (no-refs / list-of-refs)
+			    flush-pkt
+
+	no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
+				     NUL capability-list LF)
+
+	list-of-refs     =  first-ref *other-ref
+	first-ref        =  PKT-LINE(obj-id SP refname
+				     NUL capability-list LF)
+
+	other-ref        =  PKT-LINE(other-tip / other-peeled)
+	other-tip        =  obj-id SP refname LF
+	other-peeled     =  obj-id SP refname "^{}" LF
+
+	capability-list  =  capability *(SP capability)
+    capability       =  1*(ALPHA / DIGIT / "-" / "_")
+----
+
+Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
+as case-insensitive.
+
+See protocol-capabilities.txt for a list of allowed server capabilities
+and descriptions.
+
+Packfile Negotiation
+--------------------
+After reference and capabilities discovery, the client can decide
+to terminate the connection by sending a flush-pkt, telling the
+server it can now gracefully terminate (as happens with the ls-remote
+command) or it can enter the negotiation phase, where the client and
+server determine what the minimal packfile necessary for transport is.
+
+Once the client has the initial list of references that the server
+has, as well as the list of capabilities, it will begin telling the
+server what objects it wants and what objects it has, so the server
+can make a packfile that only has the objects that the client needs.
+The client will also send a list of the capabilities it supports out
+of what the server said it could do with the first 'want' statement.
+
+----
+  upload-request    =  want-list
+                       have-list
+                       compute-end
+
+  want-list         =  first-want
+                       *additional-want
+                       flush-pkt
+
+  first-want        =  PKT-LINE("want" SP obj-id SP capability-list LF)
+  additional-want   =  PKT-LINE("want" SP obj-id LF)
+
+  have-list         =  *have-line
+  have-line         =  PKT-LINE("have" SP obj-id LF)
+  compute-end       =  flush-pkt / PKT-LINE("done")
+----
+
+Clients MUST send all the SHAs it wants from the reference
+discovery phase as 'want' lines. Clients MUST send at least one
+'want' command in the request body. Clients MUST NOT mention an
+obj-id in a 'want' command which did not appear in the response
+obtained through ref discovery.
+
+If client is requesting a shallow clone, it will now send a 'deepen'
+command with the depth it is requesting.
+
+Once all the "want"s (and optional 'deepen') are transferred,
+clients MUST send a flush. If the client has all the references on
+the server, client simply flushes and disconnects.
+
+TODO: shallow/unshallow response and document the deepen command in the ABNF.
+
+Now the client will send a list of the obj-ids it has.  In multi_ack
+mode, the canonical implementation will send up to 32 of these at a
+time, then will send a flush-pkt.  The canonical implementation will
+also skip ahead and send the next 32 immediately, so that there is
+always a block of 32 "in-flight on the wire" at a time.
+
+If the client has no objects (as in the case of a non-referencing
+clone), it will skip this phase, just send it's 'done' and wait for
+the packfile.
+
+If the server reads 'have' lines, it then will respond by ACKing any
+of the obj-ids the client said it had that the server also has. The
+server will ACK obj-ids differently depending on which ack mode is
+signaled by the client.
+
+In multi_ack mode:
+
+  * the server will respond with 'ACK obj-id continue' for any common
+    commits.
+
+  * once the server has found an acceptable common base commit and is
+    ready to make a packfile, it will blindly ACK all 'have' obj-ids
+    back to the client.
+
+  * the server will then send a 'NACK' and then wait for another response
+    from the client - either a 'done' or another list of 'have' lines.
+
+In multi_ack_detailed mode:
+
+  * the server will differentiate the ACKs where it is simply signaling
+    that it is ready to send data with 'ACK obj-id ready' lines, and
+    signals the identified common commits with 'ACK obj-id common' lines.
+
+Without multi_ack:
+
+ * upload-pack sends "ACK obj-id" on the first common object it finds.
+   After that it says nothing until the client gives it a "done".
+
+ * upload-pack sends "NAK" on a flush-pkt if no common object
+   has been found yet.  If one has been found, and thus an ACK
+   was already sent, its silent on the flush-pkt.
+
+After the client has gotten enough ACK responses that it can determine
+that the server has enough information to send an efficient packfile
+(in the canonical implementation, this is determined when it has received
+enough ACKs that it can color everything left in the --date-order queue
+as common with the server, or the --date-order queue is empty), or the
+client determines that it wants to give up (in the canonical implementation,
+this is determined when the client sends 256 'have' lines without getting
+any of them ACKed by the server - meaning there is nothing in common and
+the server should just send all it's objects), then the client will send
+a 'done' command.  The 'done' command signals to the server that the client
+is ready to receive it's packfile data.
+
+However, the 256 limit *only* turns on in the canonical client
+implementation if we have received at least one "ACK %s continue"
+during a prior round.  This helps to ensure that at least one common
+ancestor is found before we give up entirely.
+
+Once the 'done' line is read from the client, the server will either
+send a final 'ACK obj-id' or it will send a 'NAK'. The server only sends
+ACK after 'done' if there is at least one common base and multi_ack or
+multi_ack_detailed is enabled. The server always sends NAK after 'done'
+if there is no common base found.
+
+Then the server will start sending it's packfile data.
+
+----
+  server-response = *ack_multi ack / nak
+  ack_multi       = PKT-LINE("ACK" SP obj-id ack_status LF)
+  ack_status      = "continue" / "common" / "ready"
+  ack             = PKT-LINE("ACK SP obj-id LF)
+  nak             = PKT-LINE("NAK" LF)
+----
+
+A simple clone may look like this (with no 'have' statements):
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+   C: 0009done\n
+
+   S: 0008NAK\n
+   S: [PACKFILE]
+----
+
+An incremental update (fetch) response might look like this:
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0000
+   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: [30 more have lines]
+   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+
+   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
+   S: 0008NAK\n
+
+   C: 0009done\n
+
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   S: [PACKFILE]
+----
+
+
+Packfile Data
+-------------
+
+Now that the client and server have done some negotiation about what
+the minimal amount of data that can be sent to the client is, the server
+will construct and send the required data in packfile format.
+
+See pack-format.txt for what the packfile itself actually looks like.
+
+If 'side-band' or 'side-band-64k' capabilities have been specified by
+the client, the server will send the packfile data multiplexed.
+
+Each packet starting with the packet-line length of the amount of data
+that follows, followed by a single byte specifying the sideband the
+following data is coming in on.
+
+In 'side-band' mode, it will send 999 data bytes plus 1 control code,
+for a total of 1000 bytes in a pkt-line.  In 'side-band-64k' mode it
+will send 65519 data bytes plus 1 control code, for a total of 65520
+bytes in a pkt-line.
+
+The sideband byte will be either a '1' or a '2'. Sideband '1' will contain
+packfile data, sideband '2' will be used for progress information that the
+client will generally print to stderr.
+
+If no 'side-band' capability was specified, the server will simply
+stream the entire packfile without multiplexing.
+
+
+Pushing Data To a Server
+========================
+
+Pushing data to a server will invoke the 'receive-pack' process on the
+server, which will allow the client to tell it which references it should
+update and then send all the data the server will need for those new
+references to be complete.  Once all the data is received and validated,
+the server will then update it's references to what the client specified.
+
+Authentication
+--------------
+
+The protocol itself contains no authentication mechanisms.  That is to be
+handled by the transport, such as SSH, before the 'receive-pack' process is
+invoked.  If 'receive-pack' is configured over the Git transport, those
+repositories will be writable by anyone who can access that port (9418) as
+that transport is unauthenticated.
+
+Reference Discovery
+-------------------
+
+The reference discovery phase is done nearly the same way as it is in the
+fetching protocol. Each reference obj-id and name on the server is sent
+in packet-line format to the client, followed by a flush packet.  The only
+real difference is that the capability listing is different - the only
+possible values are 'report-status', 'delete-refs' and 'ofs-delta'.
+
+Reference Update Request and Packfile Transfer
+----------------------------------------------
+
+Once the client knows what references the server is at, it can send a
+list of reference update requests.  For each reference on the server
+that it wants to update, it sends a line listing the obj-id currently on
+the server, the obj-id the client would like to update it to and the name
+of the reference.
+
+This list is followed by a flush packet and then the packfile that should
+contain all the objects that the server will need to complete the new
+references.
+
+The pack-file MUST NOT be sent if the only command used is 'delete'.
+
+A pack-file MUST be sent if either create or update command is used.
+An empty pack-file MUST be sent if a create or update command is
+used, and the server already obviously has the object (e.g. the
+SHA-1 is already pointed to by another ref that was listed in the
+advertisement).
+
+----
+  update-request    =  command-list [pack-file]
+
+  command-list      =  PKT-LINE(command NUL capability-list LF)
+                       *PKT-LINE(command LF)
+                       flush-pkt
+
+  command           =  create / delete / update
+  create            =  zero-id SP new-id  SP name
+  delete            =  old-id  SP zero-id SP name
+  update            =  old-id  SP new-id  SP name
+
+  old-id            =  obj-id
+  new-id            =  obj-id
+
+  pack-file         = "PACK" 24*(OCTET)
+----
+
+The server will receive the packfile, unpack it, then validate each
+reference that is being updated that it hasn't changed while the request
+was being processed (the obj-id is still the same as the old-id), and
+it will run any update hooks to make sure that the update is acceptable.
+If all of that is fine, the server will then update the references.
+
+Report Status
+-------------
+
+If the 'report-status' capability is sent by the client, then the server
+will send a short report of what happened in that update.  It will first
+list the status of the packfile unpacking as either 'unpack ok' or
+'unpack [error]'.  Then it will list the status for each of the references
+that it tried to update.  Each line be either 'ok [refname]' if the
+update was successful, or 'ng [refname] [error]' if the update was not.
+
+----
+  report-status     = unpack-status
+                      1*(command-status)
+                      flush-pkt
+
+  unpack-status     = PKT-LINE("unpack" SP unpack-result LF)
+  unpack-result     = "ok" / error-msg
+
+  command-status    = command-ok / command-fail
+  command-ok        = PKT-LINE("ok" SP refname LF)
+  command-fail      = PKT-LINE("ng" SP refname SP error-msg LF)
+
+  error-msg         = 1*(OCTECT) ; where not "ok"
+----
+
+Updates can be unsuccessful for a number of reasons.  The reference can have
+changed since the reference discovery phase was originally sent, meaning
+someone pushed in the meantime.  The reference being pushed could be a
+non-fast-forward reference and the update hooks or configuration could be
+set to not allow that, etc.  Also, some references can be updated while others
+can be rejected.
+
+An example client/server communication might look like this:
+
+----
+   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d
refs/heads/local\0report-status delete-refs ofs-delta\n
+   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
+   S: 0000
+
+   C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe
74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
+   C: 003e74730d410fcb6603ace96f1dc55ea6196122532d
5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
+   C: 0000
+   C: [PACKDATA]
+
+   S: 000aunpack ok\n
+   S: 0014ok refs/heads/debug\n
+   S: 0026ng refs/heads/master non-fast-forward\n
+----
diff --git a/Documentation/technical/protocol-capabilities.txt
b/Documentation/technical/protocol-capabilities.txt
new file mode 100644
index 0000000..3c86fc3
--- /dev/null
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -0,0 +1,188 @@
+Git Protocol Capabilities
+=========================
+
+Servers SHOULD support all capabilities defined in this document.
+
+On the very first line of the initial server response, the first
+reference is followed by a null byte and then a list of space
+delimited server capabilities.  These allow the server to declare
+what it can and cannot do to the client.
+
+Client sends space separated list of capabilities it wants.  It
+SHOULD send a subset of server capabilities, i.e do not send
+capabilities served does not advertise.  The client SHOULD NOT ask
+for capabilities the server did not say it supports.
+
+Server MUST ignore capabilities it does not understand.  Server MUST
+NOT ignore capabilities that client requested and server advertised.
+
+The 'report-status' and 'delete-refs' capabilities are sent and
+recognized by the receive-pack (push to server) process.
+
+The 'ofs-delta' capability is sent and recognized by both upload-pack
+and receive-pack protocols.
+
+All other capabilities are only recognized by the upload-pack (fetch
+from server) process.
+
+multi_ack
+---------
+
+The 'multi_ack' capability allows the server to return "ACK $SHA1
+continue" as soon as it finds a commit that it can use as a common
+base, between the client's wants and the client's have set.
+
+By sending this early, the server can potentially head off the client
+from walking any further down that particular branch of the client's
+repository history.  The client may still need to walk down other
+branches, sending have lines for those, until the server has a
+complete cut across the DAG, or the client has said "done".
+
+Without multi_ack, a client sends have lines in --date-order until
+the server has found a common base.  That means the client will send
+have lines that are already known by the server to be common, because
+they overlap in time with another branch that the server hasn't found
+a common base on yet.
+
+The client has things in caps that the server doesn't; server has
+things in lower case.
+
+       +---- u ---------------------- x
+      /             +----- y
+     /             /
+    a -- b -- c -- d -- E -- F
+       \
+        +--- Q -- R -- S
+
+If the client wants x,y and starts out by saying have F,S, the server
+doesn't know what F,S is.  Eventually the client says "have d" and
+the server sends "ACK d continue" to let the client know to stop
+walking down that line (so don't send c-b-a), but its not done yet,
+it needs a base for X. The client keeps going with S-R-Q, until a
+gets reached, at which point the server has a clear base and it all
+ends.
+
+Without multi_ack the client would have sent that c-b-a chain anyway,
+interleaved with S-R-Q.
+
+thin-pack
+---------
+
+Server can send thin packs, i.e. packs which do not contain base
+elements, if those base elements are available on clients side.
+Client requests thin-pack capability when it understands how to "thicken"
+them adding required delta bases making them independent.
+
+Client MUST NOT request 'thin-pack' capability if it
+cannot turn thin packs into proper independent packs.
+
+
+side-band, side-band-64k
+------------------------
+
+This means that server can send, and client understand multiplexed
+(muxed) progress reports and error info interleaved with the packfile
+itself.
+
+These two options are mutually exclusive.  A client should ask for
+only one of them, and a modern client always favors side-band-64k.
+
+Either mode indicates that the packfile data will be streamed broken
+up into packets of either 1000 bytes in the case of 'side_band', or
+65520 bytes in the case of 'side_band_64k'. Each packet is made up of
+a leading 4-byte pkt-line length of how much data is in the packet,
+followed by a 1-byte stream code, followed by the actual data.
+
+The stream code can be one of:
+
+ 1 - pack data
+ 2 - progress messages
+ 3 - fatal error message just before stream aborts
+
+The "side-band-64k" capability came about as a way for newer clients
+that can handle much larger packets to request packets that are
+actually crammed nearly full, while maintaining backward compatibility
+for the older clients.
+
+Further, with side-band and its 1000 byte messages, it's actually
+999 bytes of payload and 1 byte for the stream code. With side-band-64k,
+same deal, you have 65519 bytes of data and 1 byte for the stream code.
+
+The client MUST send only maximum of one of "side-band" and "side-
+band-64k".  Server MUST favor side-band-64k if client requests both.
+
+ofs-delta
+---------
+
+Server can send, and client understand PACKv2 with delta refering to
+its base by position in pack rather than by SHA-1.  Its that they can
+send/read OBJ_OFS_DELTA, aka type 6 in a pack file.
+
+shallow
+-------
+
+This capability adds "deepen", "shallow" and "unshallow" commands to
+the  fetch-pack/upload-pack protocol so clients can request shallow
+clones.
+
+no-progress
+-----------
+
+The client was started with "git clone -q" or something, and doesn't
+want that side band 2.  Basically the client just says "I do not
+wish to receive stream 2 on sideband, so do not send it to me, and if
+you did, I will drop it on the floor anyway".  However, the sideband
+channel 3 is still used for error responses.
+
+include-tag
+-----------
+
+The 'include-tag' capability is about sending tags if we are sending
+objects they point to.  If we pack an object to the client, and a tag
+points exactly at that object, we pack the tag too.  In general this
+allows a client to get all new tags when it fetches a branch, in a
+single network connection.
+
+Clients MAY always send include-tag, hardcoding it into a request.
+The decision for a client to request include-tag only has to do with
+the client's desires for tag data, whether or not a server had
+advertised objects in the refs/tags/* namespace.
+
+Clients SHOULD NOT send include-tag if remote.name.tagopt was set to
+--no-tags, as the client doesn't want tag data.
+
+Servers MUST accept include-tag without error or warning, even if the
+server does not understand or support the option.
+
+Servers SHOULD pack the tags if their referrant is packed and the
+client has requested include-tag.
+
+Clients MUST be prepared for the case where a server has ignored
+include-tag and has not actually sent tags in the pack.  In such
+cases the client SHOULD issue a subsequent fetch to acquire the tags
+that include-tag would have otherwise given the client.
+
+The server SHOULD send include-tag, if it supports it, irregardless
+of whether or not there are tags available.
+
+report-status
+-------------
+
+The upload-pack process can receive a 'report-status' capability,
+which tells it that the client wants a report of what happened after
+a packfile upload and reference update.  If the pushing client requests
+this capability, after unpacking and updating references the server
+will respond with whether the packfile unpacked successfully and if
+each reference was updated successfully.  If any of those were not
+successful, it will send back an error message.  See pack-protocol.txt
+for example messages.
+
+delete-refs
+-----------
+
+If the server sends back the 'delete-refs' capability, it means that
+it is capable of accepting an all-zeroed SHA-1 value as the target
+value of a reference update.  It is not sent back by the client, it
+simply informs the client that it can be sent zeroed SHA-1 values
+to delete references.
+
diff --git a/Documentation/technical/protocol-common.txt
b/Documentation/technical/protocol-common.txt
new file mode 100644
index 0000000..ddf9912
--- /dev/null
+++ b/Documentation/technical/protocol-common.txt
@@ -0,0 +1,96 @@
+Documentation Common to Pack and Http Protocols
+===============================================
+
+ABNF Notation
+-------------
+
+ABNF notation as described by RFC 5234 is used within the protocol documents,
+except the following replacement core rules are used:
+----
+  HEXDIG    =  DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
+----
+
+We also define the following common rules:
+----
+  NUL       =  %x00
+  zero-id   =  40*"0"
+  obj-id    =  40*(HEXDIGIT)
+
+  refname  =  "HEAD"
+  refname /=  "refs/" <see discussion below>
+----
+
+A refname is a hierarichal octet string beginning with "refs/" and
+not violating the 'git-check-ref-format' command's validation rules.
+More generally, they:
+
+. They can include slash `/` for hierarchical (directory)
+  grouping, but no slash-separated component can begin with a
+  dot `.`.
+
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.
+
+. They cannot have two consecutive dots `..` anywhere.
+
+. They cannot have ASCII control characters (i.e. bytes whose
+  values are lower than \040, or \177 `DEL`), space, tilde `~`,
+  caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+  or open bracket `[` anywhere.
+
+. They cannot end with a slash `/` nor a dot `.`.
+
+. They cannot end with the sequence `.lock`.
+
+. They cannot contain a sequence `@{`.
+
+. They cannot contain a `\\`.
+
+
+pkt-line Format
+---------------
+
+Much (but not all) of the payload is described around pkt-lines.
+
+A pkt-line is a variable length binary string.  The first four bytes
+of the line, the pkt-len, indicates the total length of the line,
+in hexadecimal.  The pkt-len includes the 4 bytes used to contain
+the length's hexadecimal representation.
+
+A pkt-line MAY contain binary data, so implementors MUST ensure
+pkt-line parsing/formatting routines are 8-bit clean.
+
+A non-binary line SHOULD BE terminated by an LF, which if present
+MUST be included in the total length.
+
+The maximum length of a pkt-line's data component is 65520 bytes.
+Implementations MUST NOT send pkt-line whose length exceeds 65524
+(65520 bytes of payload + 4 bytes of length data).
+
+Implementations SHOULD NOT send an empty pkt-line ("0004").
+
+A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
+is a special case and MUST be handled differently than an empty
+pkt-line ("0004").
+
+----
+  pkt-line     =  data-pkt / flush-pkt
+
+  data-pkt     =  pkt-len pkt-payload
+  pkt-len      =  4*(HEXDIG)
+  pkt-payload  =  (pkt-len - 4)*(OCTET)
+
+  flush-pkt    = "0000"
+----
+
+Examples (as C-style strings):
+
+----
+  pkt-line          actual value
+  ---------------------------------
+  "0006a\n"         "a\n"
+  "0005a"           "a"
+  "000bfoobar\n"    "foobar\n"
+  "0004"            ""
+----
-- 
1.6.5.2.340.g000a3e.dirty

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-10-31  2:06 ` Shawn O. Pearce
@ 2009-10-31 20:12   ` Johannes Sixt
  0 siblings, 0 replies; 25+ messages in thread
From: Johannes Sixt @ 2009-10-31 20:12 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Scott Chacon, git list

Shawn O. Pearce schrieb:
> Scott Chacon <schacon@gmail.com> wrote:
>> +Currently only 'host' is allowed in the extra information.  It's
> 
> No.  We should make this a MUST.  As in:
> 
> 	Only host-parameter is allowed in the git-proto-request.
> 	Clients MUST NOT attempt to send additional parameters.
> 
> Sending another header can cause older git-daemons to lock up.

I think you are making a wrong case here: Older git-daemons that lock up 
are security holes because they allow DoS attacks, and any decent admin 
will want to upgrade to a fixed git-daemon anyway.

Fixed git-daemons can allow extra information in addition to 'host'. I 
know you argued otherwise when you submitted the fix to git-daemon, but I 
think you were wrong already back then.

-- Hannes

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-10-29 17:35 Scott Chacon
  2009-10-30 22:07 ` Junio C Hamano
@ 2009-10-31  2:06 ` Shawn O. Pearce
  2009-10-31 20:12   ` Johannes Sixt
  1 sibling, 1 reply; 25+ messages in thread
From: Shawn O. Pearce @ 2009-10-31  2:06 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list

Scott Chacon <schacon@gmail.com> wrote:
> The protocol-common.txt is taken from Shawns
> http-protocol.txt that was in common with packfile protocol.  Shawn,
> is that the best way to share that info?

Yup, I think that's the easiest way to do it.

> diff --git a/Documentation/technical/pack-protocol.txt
> +
> +Transports
> +----------
> +The file:// transport simply runs the 'upload-pack' or 'receive-pack'
> +process locally.

You may want to mention that a pipe is used to communicate with
the local process.

> +Git Protocol
> +------------
> +   git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
> +   request-command   = 'git-upload-pack' / 'git-receive-pack' /
> +                       'git-upload-archive'   ; case sensitive
> +   pathname          = *( %x01-ff ) ; exclude NUL
> +   host-parameter    = 'host' "=" hostname [ ":" port ]

Use double quotes for the request-command items and for the host
literal in host-parameter.

> +Currently only 'host' is allowed in the extra information.  It's

No.  We should make this a MUST.  As in:

	Only host-parameter is allowed in the git-proto-request.
	Clients MUST NOT attempt to send additional parameters.

Sending another header can cause older git-daemons to lock up.

> +   $ echo -e -n \
> +     "0039git-upload-pack /schacon/gitbook.git\0host=github.com\0" |
> +     nc -v github.com 9418

I guess a decent example, but lets use example.com in the
documentation.

> +SSH Protocol
> +------------
> +
> +   $ ssh git.example.com 'git-upload-pack /project.git'

/project.git may be wrapped in single quotes if it contains shell
unsafe characters, like spaces.  So really the invocation is
more like:

  $ ssh git.example.com "git-upload-pack '/my project.git'"

> +In an ssh:// format URI, it's absolute in the URI, so the '/' after

Unless its ssh://user@example.com/~alice/project.git, in which case
we execute

  ssh user@example.com 'git-upload-pack ~alice/project.git'.

> +Reference Discovery
> +-------------------
> +
> +When the client initially connects the server will immediately respond
> +with a listing of each reference it has (all branches and tags) along
> +with the commit SHA that each reference currently points to.
> +
> +   $ echo -e -n \
> +     "0039git-upload-pack /schacon/gitbook.git\0host=github.com\0" |
> +      nc -v github.com 9418

Same remark about example.com in docs.

> +HEAD is not included if its detached - that is, if HEAD is not a
> +symbolic reference, a pointer to another branch, it is not included
> +in the initial server response.

Really?  I thought it was.

> +Packfile Negotiation
> +--------------------
> +After reference and capabilities discovery, the client can decide
> +to terminate the connection (as happens with the ls-remote command)

In this case the client SHOULD send flush-pkt before closing so
the server can gracefully terminate, rather than ungracefully exit
while waiting on input.

I don't know why this is, the server should be more robust here,
but its historical precendent and there are older servers still,
so we should document it.

> +----
> +	upload-request    =  want-list
> +	                     have-list
> +	                     compute-end

The shallow stuff goes between want-list and have-list, and actually
has a full round trip between the client and the server.  I didn't
get to documenting that yet.  We'll need to do that soon.

> +Once all the "want"s (and optional 'deepen') [...]
> +
> +TODO: shallow/unshallow response

Also document the deepen command above in the ABNF.

> +Now the client will send a list of the obj-ids it has.  In multi-ack
> +mode, the canonical implementation will send up to 32 of these at a

Also, in multi_ack mode the canonical implementation will skip
ahead and send the next 32 immediately, so that there is always
a block of 32 "in-flight on the wire" at a time.

This means some pipe buffering is required, at least 1604 bytes
on the client side.  IIRC POSIX pipes (and some pure-software ones
e.g. the Java default in-memory pipe) only promise 512 bytes.

But for some reason I recall I had computed this out at just over
2100 bytes, but right now I can't recall why that is.

> +If the server reads 'have' lines, it then will respond by ACKing any
> +of the obj-ids the client said it had that the server also has.  Or,
> +once the server has found an acceptable common base commit and is
> +ready to make a packfile, it will blindly ACK all 'have' obj-ids back
> +to the client.  Then it will send a 'NACK' and then wait for
> +another response from the client - either a 'done' or another list of
> +'have' lines.

If this is a description of non-multi_ack mode, its wrong.

Without multi_ack:

  * upload-pack sends "ACK %s\n" on the first common object it finds.
    After that it says nothing until the client gives it a "done".

  * upload-pack sends "NAK\n" on a flush-pkt if no common object
    has been found yet.  If one has been found, and thus an ACK
    was already sent, its silent on the flush-pkt.

> +In multi-ack mode, the server will respond with 'ACK obj-id continue'
> +for common commits, otherwise it will just respond with 'ACK obj-id'
> +lines.  In multi-ack-detailed mode, it will differentiate the ACKs

Its multi_ack and mulit_ack_detailed.  For historical reasons we
use _ in these not -.

Also, in multi_ack mode we never use "ACK %s\n", only the newer
"ACK %s continue\n" gets used.  This is also true in multi_ack_detailed,
where we only use common/ready and none of the other forms.

> +After the client has gotten 'ACK obj-id' responses for all it's
> +references, or has sent more than 256 references and decides to give
> +up, it will send a 'done' command, which signals to the server that it
> +is ready to receive it's packfile data.

This isn't really correct.  The client won't get an "ACK obj-id"
for its refs.  Really the client's termination condition is that
it has received enough "ACK obj-id"'s that it can color everything
left in the --date-order queue as common with the server, or the
--date-order queue is empty.

The 256 thing isn't 256 references.  Its the client SHOULD abort if
it has 256 have lines without receiving a single ACK, of any kind,
from the server.  In such a case the client has just walked down
some long path where there is nothing in common, and maybe that
really is the case, so it should just give up.

Unfortunately this rule is dicey because if a client is really far
ahead of the remote peer its fetching from it could go down that
256 commit chain and give up too soon, and download the entire
project all over again.

Fortunately, the 256 limit *only* turns on in the canonical client
implementation if we have received at least one "ACK %s continue"
during a prior round.  This helps to ensure that at least one common
ancestor is found before we give up entirely.

> +Once the 'done' line is read from the client, the server will either
> +send a final 'ACK obj-id' line if it is in multi-ack mode and has found
> +a common base, or it will send a 'NAK' if it has still not found a common
> +base; then the server will start sending it's packfile data.

This needs to be more clear.

It always sends NAK after done if there is no common base found.

It only sends ACK after done if there is at least one common base
and multi_ack or multi_ack_detailed is enabled.

> +----
> +	server-response   =  *acks
> +	                     nack

NAK is optional if ACKs were sent, so really I think this entire block is:

  server-response = *ack_multi ack / nak
  ack_multi       = PKT-LINE("ACK" SP obj-id ack_status LF)
  ack_status      = "continue" / "common" / "ready"
  ack             = PKT-LINE("ACK SP obj-id LF)
  nak             = PKT-LINE("NAK" LF)

> +    acks              =  *ack

Some sort of tab/space error on leading indent, but I'd drop this rule.

> +	nack              =  PKT-LINE("NACK" LF)

This is actually spelled "NAK" (no C).  See my rewrite above.


> +Packfile Data
> +-------------
> +
> +If 'side-band' or 'side-band-64k' capabilities have been specified by
> +the client, the server will send the packfile data multiplexed - it
> +will be sent in packets of either 1000 bytes or 64k, depending on which

Its 999 data bytes, 1 control code, for a total of 1000 bytes in
a pkt-line, or 65519 data bytes, 1 control code, for a total of
65520 bytes in a pkt-line.  You imply 65536 bytes of data here by
saying 64k.  Don't round up.

> +sideband type was specified, with each packet starting with the packet-line
> +format of the amount of data that follows, followed by a single byte

Not format, length.

> +If no 'side-band' capability was specified, the server will simply
> +stream the entire packfile.

Without multiplexing.

> +Reference Discovery
> +-------------------
> +
> +instead of following a null byte, the capabilities follow a space.

No, the follow a NUL.

> +	capability-list  =  capability *(SP capability)
> +    capability       =  1*(ALPHA / DIGIT / "-" / "_")

Tab/space error on indent.

> +Reference Update Request and Packfile Transfer
> +----------------------------------------------
> +
> +This list is followed by a flush packet and then the packfile that should
> +contain all the objects that the server will need to complete the new
> +references.

The pack-file MUST NOT be sent if the only command used is 'delete'.

A pack-file MUST be sent if either create or update command is used.
An empty pack-file MUST be sent if a create or update command is
used, and the server already obviously has the object (e.g. the
SHA-1 is already pointed to by another ref that was listed in the
advertisement).

> +----
> +	update-request    =  command-list pack-file

Add [] around pack-file to make it optional.

> +An example client/server communication might look like this:
> +
> +----
> +   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d HEAD report-status
> delete-refs ofs-delta\n

There's a NUL before the capabilities.  Also, HEAD usually is not
sent in the advertisement, its weird to update HEAD via push.

> +   S: 000aunpack ok\n
> +   S: 000aok refs/heads/debug\n
> +   S: 000ang refs/heads/master non-fast-forward\n

Your pkt-len is all wrong here, there's no way each of those is 10
bytes long.  :-)

Please double check all of the pkt-lens used in the document, its
annoying, but if we are trying to really document the protocol its
a good idea that all examples presented are accurate.

> diff --git a/Documentation/technical/protocol-capabilities.txt
> +
> +multi-ack
> +---------
> +
> +The 'multi-ack' capability allows the server to return "ACK $SHA1

Its spelled 'multi_ack'.

Otherwise, nice writeup of this capability.

> +side-band, side-band-64k
> +------------------------

You need to explain how the packet length is actually 1 byte larger
than the data payload, with a stream code in that first byte of:

  1 - pack data
  2 - progress messages
  3 - fatal error message just before stream aborts

Further, with side-band and its 1000 byte messages, its actually
999 bytes of payload and 1 byte for the stream code.

With side-band-64k, same deal, you have 65519 bytes of data and 1
byte for the stream code.

> +shallow
> +-------

This capability also adds "shallow" and "unshallow" commands to
the fetch-pack/upload-pack protocol.  I haven't had time to study
what impact this has, as we haven't implemented shallow support
yet in JGit.

> +no-progress
> +-----------
> +
> +The client was started with "git clone -q" or something, and doesn't
> +want that side brand 2.  Basically the client just says "I do not

s/brand/band/

> +include-tag
> +-----------
> +
> +The 'include-tag' capability is about sending tags if we are sending
> +objects they point to.  If we pack an object to the client, and a tag
> +points exactly at that object, we pack the tag too.  In general this
> +allows a client to get all new tags when it fetches a branch, in a
> +single network connection.

Elaborate to say "annotated tag" at least once here.

> +Servers SHOULD support all capabilities defined in this document.

This should be at the top of this document, not inside of the
include-tag section.

We should also document the following from receive-pack:

 * report-status
 * delete-refs

> diff --git a/Documentation/technical/protocol-common.txt
...
> +	data-pkt     =  pkt-len pkt-payload
> +    pkt-len      =  4*(HEXDIG)
> +	pkt-payload  =  (pkt-len - 4)*(OCTET)

Some sort of odd tab/space error here on the pkt-len line.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH] Update packfile transfer protocol documentation
  2009-10-29 17:35 Scott Chacon
@ 2009-10-30 22:07 ` Junio C Hamano
  2009-10-31  2:06 ` Shawn O. Pearce
  1 sibling, 0 replies; 25+ messages in thread
From: Junio C Hamano @ 2009-10-30 22:07 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git list, Shawn O. Pearce

Scott Chacon <schacon@gmail.com> writes:

> The technical documentation for the packfile protocol is both sparse and
> incorrect.  This documents the fetch-pack/upload-pack and send-pack/
> receive-pack protocols much more fully.

Thanks for starting this.  There were a few little things I noticed
(e.g. SHA when it should say SHA-1 or "object name") but we can fix them
up in-tree.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH] Update packfile transfer protocol documentation
@ 2009-10-29 17:35 Scott Chacon
  2009-10-30 22:07 ` Junio C Hamano
  2009-10-31  2:06 ` Shawn O. Pearce
  0 siblings, 2 replies; 25+ messages in thread
From: Scott Chacon @ 2009-10-29 17:35 UTC (permalink / raw)
  To: git list; +Cc: Shawn O. Pearce

The technical documentation for the packfile protocol is both sparse and
incorrect.  This documents the fetch-pack/upload-pack and send-pack/
receive-pack protocols much more fully.

Add documentation from Shawn's upcoming http-protocol docs that is shared
by the packfile protocol. protocol-common.txt describes ABNF notation
amendments, refname rules and the packet line format.

Add documentation on the various capabilities supported by the
upload-pack and receive-pack protocols. protocol-capabilities.txt describes
multi-ack, thin-pack, side-band[-64k], ofs-delta, shallow, no-progress
and include-tag.

Signed-Off-By: Scott Chacon <schacon@gmail.com>
---

Some of this documentation is in RFC style and some of it is really
not - I apologize for that.  However, I think it's a good starting
point - certainly better than the docs in there now.  Some of this was
taken from the gitserver-rfc stuff I did several months ago, and I've
tried to include updates I got from Jakub and others on issues with
that document.  The protocol-common.txt is taken from Shawns
http-protocol.txt that was in common with packfile protocol.  Shawn,
is that the best way to share that info?

 Documentation/technical/pack-protocol.txt         |  502 +++++++++++++++++++--
 Documentation/technical/protocol-capabilities.txt |  146 ++++++
 Documentation/technical/protocol-common.txt       |   97 ++++
 3 files changed, 704 insertions(+), 41 deletions(-)
 create mode 100644 Documentation/technical/protocol-capabilities.txt
 create mode 100644 Documentation/technical/protocol-common.txt

diff --git a/Documentation/technical/pack-protocol.txt
b/Documentation/technical/pack-protocol.txt
index 9cd48b4..9222a10 100644
--- a/Documentation/technical/pack-protocol.txt
+++ b/Documentation/technical/pack-protocol.txt
@@ -1,41 +1,461 @@
-Pack transfer protocols
-=======================
-
-There are two Pack push-pull protocols.
-
-upload-pack (S) | fetch/clone-pack (C) protocol:
-
-	# Tell the puller what commits we have and what their names are
-	S: SHA1 name
-	S: ...
-	S: SHA1 name
-	S: # flush -- it's your turn
-	# Tell the pusher what commits we want, and what we have
-	C: want name
-	C: ..
-	C: want name
-	C: have SHA1
-	C: have SHA1
-	C: ...
-	C: # flush -- occasionally ask "had enough?"
-	S: NAK
-	C: have SHA1
-	C: ...
-	C: have SHA1
-	S: ACK
-	C: done
-	S: XXXXXXX -- packfile contents.
-
-send-pack | receive-pack protocol.
-
-	# Tell the pusher what commits we have and what their names are
-	C: SHA1 name
-	C: ...
-	C: SHA1 name
-	C: # flush -- it's your turn
-	# Tell the puller what the pusher has
-	S: old-SHA1 new-SHA1 name
-	S: old-SHA1 new-SHA1 name
-	S: ...
-	S: # flush -- done with the list
-	S: XXXXXXX --- packfile contents.
+Packfile transfer protocols
+===========================
+
+Git supports transferring data in packfiles over the ssh://, git:// and
+file:// transports.  There exist two sets of protocols, one for pushing
+data from a client to a server and another for fetching data from a
+server to a client.  All three transports (ssh, git, file) use the same
+protocol to transfer data.
+
+The processes invoked in the canonical Git implementation are 'upload-pack'
+on the server side and 'fetch-pack' on the client side for fetching data;
+then 'receive-pack' on the server and 'send-pack' on the client for pushing
+data.  The protocol functions to have a server tell a client what is
+currently on the server, then for the two to negotiate the smallest amount
+of data to send in order to fully update one or the other.
+
+Transports
+----------
+There are three transports over which the packfile protocol is
+initiated.  The Git transport is a simple, unauthenticated server that
+simply takes the command (almost always 'upload-pack', though Git
+servers can be configured to be globally writable, in which 'receive-
+pack' initiation is also allowed) with which the client wishes to
+communicate and executes it and connects it to the requesting
+process.
+
+In the SSH transport, the client basically just runs the 'upload-pack'
+or 'receive-pack' process on the server over the SSH protocol and then
+communicates with that invoked process over the SSH connection.
+
+The file:// transport simply runs the 'upload-pack' or 'receive-pack'
+process locally.
+
+Git Protocol
+------------
+
+The Git protocol starts off by sending "git-receive-pack 'repo.git'"
+on the wire using the pkt-line format, followed by a null byte and a
+hostname paramater, terminated by a null byte.
+
+   0032git-upload-pack /project.git\0host=myserver.com\0
+
+--
+   git-proto-request = request-command SP pathname NUL [ host-parameter NUL ]
+   request-command   = 'git-upload-pack' / 'git-receive-pack' /
+                       'git-upload-archive'   ; case sensitive
+   pathname          = *( %x01-ff ) ; exclude NUL
+   host-parameter    = 'host' "=" hostname [ ":" port ]
+--
+
+Currently only 'host' is allowed in the extra information.  It's
+for the git-daemon name based virtual hosting.  See --interpolated-
+path option to git daemon, with the %H/%CH format characters.
+
+Basically what the Git client is doing to connect to an 'upload-pack'
+process on the server side over the Git protocol is this:
+
+   $ echo -e -n \
+     "0039git-upload-pack /schacon/gitbook.git\0host=github.com\0" |
+     nc -v github.com 9418
+
+
+SSH Protocol
+------------
+
+Initiating the upload-pack or receive-pack processes over SSH is
+simply executing the binary on the server via SSH remote execution.
+It is basically equivalent to running this:
+
+   $ ssh git.example.com 'git-upload-pack /project.git'
+
+For a server to support Git pushing and pulling for a given user over
+SSH, that user needs to be able to execute one or both of those
+commands via the SSH shell that they are provided on login.  On some
+systems, that shell access is limited to only being able to run those
+two commands, or even just one of them.
+
+In an ssh:// format URI, it's absolute in the URI, so the '/' after
+the host name (or port number) is sent as an argument, which is then
+read by the remote git-upload-pack exactly as is, so it's effectively
+an absolute path in the remote filesystem.
+
+          git clone ssh://user@example.com/project.git
+                            |
+                            v
+       ssh user@example.com 'git-upload-pack /project.git'
+
+In a "user@host:path" format URI, its relative to the user's home
+directory, because the Git client will run:
+
+             git clone user@example.com:project.git
+                              |
+                              v
+        ssh user@example.com 'git-upload-pack project.git'
+
+
+
+Fetching Data From a Server
+===========================
+
+When one Git repository wants to get all the data that a second
+repository has, the first can 'fetch' from the second.  This
+operation determines what data the server has that the client does
+not then streams that data down to the client in packfile format.
+
+The server side binaries need to be executable as 'git-upload-pack'
+for fetching and 'git-receive-pack' for pushing over SSH, since the
+Git clients will connect to the server and attempt to run that command
+directly.  Over the Git protocol, one could write their own daemon
+that sees that the client is trying to invoke those commands and
+simply handle the requests.
+
+
+Reference Discovery
+-------------------
+
+When the client initially connects the server will immediately respond
+with a listing of each reference it has (all branches and tags) along
+with the commit SHA that each reference currently points to.
+
+   $ echo -e -n \
+     "0039git-upload-pack /schacon/gitbook.git\0host=github.com\0" |
+      nc -v github.com 9418
+   00887217a7c7e582c46cec22a130adf4b9d7d950fba0 HEAD\0multi_ack \
+     thin-pack side-band side-band-64k ofs-delta shallow no-progress \
+     include-tag
+   00441d3fcd5ced445d1abc402225c0b8a1299641f497 refs/heads/integration
+   003f7217a7c7e582c46cec22a130adf4b9d7d950fba0 refs/heads/master
+   003cb88d2441cac0977faf98efc80305012112238d9d refs/tags/v0.9
+   003c525128480b96c89e6418b1e40909bf6c5b2d580f refs/tags/v1.0
+   003fe92df48743b7bc7d26bcaabfddde0a1e20cae47c refs/tags/v1.0^{}
+   0000
+
+Server SHOULD terminate each non-flush line
+using LF ("\n") terminator; client MUST NOT complain if there is no
+terminator.
+
+The returned response is a pkt-line stream describing each ref and
+its known value.  The stream SHOULD be sorted by name according to
+the C locale ordering.  The stream SHOULD include the default ref
+named 'HEAD' as the first ref.  The stream MUST include capability
+declarations behind a NUL on the first ref.
+
+HEAD is not included if its detached - that is, if HEAD is not a
+symbolic reference, a pointer to another branch, it is not included
+in the initial server response.  The client pattern matches the
+advertisements against the fetch refspec, which is "refs/heads/
+*:refs/remotes/origin/*" by default.  HEAD doesn't match the LHS, so
+it doesn't get wanted by the client.
+
+----
+	advertised-refs  =  (no-refs / list-of-refs)
+	                    flush-pkt
+
+	no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
+	                             NUL capability-list LF)
+
+	list-of-refs     =  first-ref *other-ref
+	first-ref        =  PKT-LINE(obj-id SP refname
+	                             NUL capability-list LF)
+
+	other-ref        =  PKT-LINE(other-tip / other-peeled)
+	other-tip        =  obj-id SP refname LF
+	other-peeled     =  obj-id SP refname "^{}" LF
+
+	capability-list  =  capability *(SP capability)
+    capability       =  1*(ALPHA / DIGIT / "-" / "_")
+----
+
+Server and client SHOULD use lowercase for SHA1, both MUST treat SHA1
+as case-insensitive.
+
+See protocol-capabilities.txt for a list of allowed server capabilities
+and descriptions.
+
+Packfile Negotiation
+--------------------
+After reference and capabilities discovery, the client can decide
+to terminate the connection (as happens with the ls-remote command)
+or it can enter the negotiation phase, where the client and server
+determine what the minimal packfile necessary for transport is.
+
+Once the client has the initial list of references that the server
+has, as well as the list of capabilities, it will begin telling the
+server what objects it wants and what objects it has, so the server
+can make a packfile that only has the objects that the client needs.
+The client will also send a list of the capabilities it supports out
+of what the server said it could do with the first 'want' statement.
+
+----
+	upload-request    =  want-list
+	                     have-list
+	                     compute-end
+
+	want-list         =  first-want
+	                     *additional-want
+						 flush-pkt
+
+	first-want        =  PKT-LINE("want" SP obj-id SP capability-list LF)
+	additional-want   =  PKT-LINE("want" SP obj-id LF)
+
+	have-list         =  *have-line
+	have-line         =  PKT-LINE("have" SP obj-id LF)
+	compute-end       =  flush-pkt / PKT-LINE("done")
+----
+
+Clients MUST send all the SHAs it wants from the reference
+discovery phase as 'want' lines. Clients MUST send at least one
+'want' command in the request body. Clients MUST NOT mention an
+obj-id in a 'want' command which did not appear in the response
+obtained through ref discovery.
+
+If client is requesting a shallow clone, it will now send a 'deepen'
+command with the depth it is requesting.
+
+Once all the "want"s (and optional 'deepen') are transferred,
+clients MUST send a flush. If the client has all the references on
+the server, client simply flushes and disconnects.
+
+TODO: shallow/unshallow response
+
+Now the client will send a list of the obj-ids it has.  In multi-ack
+mode, the canonical implementation will send up to 32 of these at a
+time, then will flush and wait for the server to respond.  If the
+client has no objects (as in the case of a non-referencing clone),
+it will skip this phase, just send it's 'done' and wait for the
+packfile.
+
+If the server reads 'have' lines, it then will respond by ACKing any
+of the obj-ids the client said it had that the server also has.  Or,
+once the server has found an acceptable common base commit and is
+ready to make a packfile, it will blindly ACK all 'have' obj-ids back
+to the client.  Then it will send a 'NACK' and then wait for
+another response from the client - either a 'done' or another list of
+'have' lines.
+
+In multi-ack mode, the server will respond with 'ACK obj-id continue'
+for common commits, otherwise it will just respond with 'ACK obj-id'
+lines.  In multi-ack-detailed mode, it will differentiate the ACKs
+where it is simply signaling that it is ready to send data with
+'ACK obj-id ready' lines, and signals the identified common commits
+with 'ACK obj-id common' lines.
+
+After the client has gotten 'ACK obj-id' responses for all it's
+references, or has sent more than 256 references and decides to give
+up, it will send a 'done' command, which signals to the server that it
+is ready to receive it's packfile data.
+
+Once the 'done' line is read from the client, the server will either
+send a final 'ACK obj-id' line if it is in multi-ack mode and has found
+a common base, or it will send a 'NAK' if it has still not found a common
+base; then the server will start sending it's packfile data.
+
+----
+	server-response   =  *acks
+	                     nack
+
+    acks              =  *ack
+	ack               =  PKT-LINE("ACK" SP obj-id continue LF)
+	nack              =  PKT-LINE("NACK" LF)
+----
+
+A simple clone may look like this (with no 'have' statements):
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0032want 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: 0032want 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+   C: 0009done\n
+
+   S: 0008NAK\n
+   S: [PACKFILE]
+----
+
+An incremental update (fetch) response might look like this:
+
+----
+   C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d\0multi_ack \
+     side-band-64k ofs-delta\n
+   C: 0032want 7d1665144a3a975c05f1f43902ddaf084e784dbe\n
+   C: 0032want 5a3f6be755bbb7deae50065988cbfa1ffa9ab68a\n
+   C: 0000
+   C: 0032have 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01\n
+   C: [30 more have lines]
+   C: 0032have 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   C: 0000
+
+   S: 003aACK 7e47fe2bd8d01d481f44d7af0531bd93d3b21c01 continue\n
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d continue\n
+   S: 0008NAK\n
+
+   C: 0009done\n
+
+   S: 003aACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
+   S: [PACKFILE]
+----
+
+
+Packfile Data
+-------------
+
+Now that the client and server have done some negotiation about what
+the minimal amount of data that can be sent to the client is, the server
+will construct and send the required data in packfile format.
+
+See pack-format.txt for what the packfile itself actually looks like.
+
+If 'side-band' or 'side-band-64k' capabilities have been specified by
+the client, the server will send the packfile data multiplexed - it
+will be sent in packets of either 1000 bytes or 64k, depending on which
+sideband type was specified, with each packet starting with the packet-line
+format of the amount of data that follows, followed by a single byte
+specifying the sideband the following data is coming in on.
+
+The sideband byte will be either a '1' or a '2'. Sideband '1' will contain
+packfile data, sideband '2' will be used for progress information that the
+client will generally print to stderr.
+
+If no 'side-band' capability was specified, the server will simply
+stream the entire packfile.
+
+
+Pushing Data To a Server
+========================
+
+Pushing data to a server will invoke the 'receive-pack' process on the
+server, which will allow the client to tell it which references it should
+update and then send all the data the server will need for those new
+references to be complete.  Once all the data is received and validated,
+the server will then update it's references to what the client specified.
+
+Authentication
+--------------
+
+The protocol itself contains no authentication mechanisms.  That is to be
+handled by the transport, such as SSH, before the 'receive-pack' process is
+invoked.  If 'receive-pack' is configured over the Git transport, those
+repositories will be writable by anyone who can access that port (9418) as
+that transport is unauthenticated.
+
+Reference Discovery
+-------------------
+
+The reference discovery phase is done nearly the same way as it is in the
+fetching protocol. Each reference obj-id and name on the server is sent
+in packet-line format to the client, followed by a flush packet.  The only
+real difference is that the capability listing is different - the only
+possible values are 'report-status', 'delete-refs' and 'ofs-delta', and
+instead of following a null byte, the capabilities follow a space.
+
+----
+	advertised-refs  =  (no-refs / list-of-refs)
+	                    flush-pkt
+
+	no-refs          =  PKT-LINE(zero-id SP "capabilities^{}"
+	                             NUL capability-list LF)
+
+	list-of-refs     =  first-ref *other-ref
+	first-ref        =  PKT-LINE(obj-id SP refname
+	                             SP capability-list LF)
+
+	other-ref        =  PKT-LINE(other-tip / other-peeled)
+	other-tip        =  obj-id SP refname LF
+	other-peeled     =  obj-id SP refname "^{}" LF
+
+	capability-list  =  capability *(SP capability)
+    capability       =  1*(ALPHA / DIGIT / "-" / "_")
+----
+
+Reference Update Request and Packfile Transfer
+----------------------------------------------
+
+Once the client knows what references the server is at, it can send a
+list of reference update requests.  For each reference on the server
+that it wants to update, it sends a line listing the obj-id currently on
+the server, the obj-id the client would like to update it to and the name
+of the reference.
+
+This list is followed by a flush packet and then the packfile that should
+contain all the objects that the server will need to complete the new
+references.
+
+----
+	update-request    =  command-list pack-file
+
+	command-list      =  PKT-LINE(command NUL capability-list LF)
+	                     *PKT-LINE(command LF)
+	                     flush-pkt
+
+	command           =  create / delete / update
+	create            =  zero-id SP new-id  SP name
+	delete            =  old-id  SP zero-id SP name
+	update            =  old-id  SP new-id  SP name
+
+	old-id            =  obj-id
+	new-id            =  obj-id
+
+	pack-file         = "PACK" 24*(OCTET)
+----
+
+The server will receive the packfile, unpack it, then validate each
+reference that is being updated that it hasn't changed while the request
+was being processed (the obj-id is still the same as the old-id), and
+it will run any update hooks to make sure that the update is acceptable.
+If all of that is fine, the server will then update the references.
+
+Report Status
+-------------
+
+If the 'report-status' capability is sent by the client, then the server
+will send a short report of what happened in that update.  It will first
+list the status of the packfile unpacking as either 'unpack ok' or
+'unpack [error]'.  Then it will list the status for each of the references
+that it tried to update.  Each line be either 'ok [refname]' if the
+update was successful, or 'ng [refname] [error]' if the update was not.
+
+----
+	report-status     = unpack-status
+	                    1*(command-status)
+	                    flush-pkt
+
+	unpack-status     = PKT-LINE("unpack" SP unpack-result LF)
+	unpack-result     = "ok" / error-msg
+
+	command-status    = command-ok / command-fail
+	command-ok        = PKT-LINE("ok" SP refname LF)
+	command-fail      = PKT-LINE("ng" SP refname SP error-msg LF)
+
+	error-msg         = 1*(OCTECT) ; where not "ok"
+----
+
+Updates can be unsuccessful for a number of reasons.  The reference can have
+changed since the reference discovery phase was originally sent, meaning
+someone pushed in the meantime.  The reference being pushed could be a
+non-fast-forward reference and the update hooks or configuration could be
+set to not allow that, etc.  Also, some references can be updated while others
+can be rejected.
+
+An example client/server communication might look like this:
+
+----
+   S: 007c74730d410fcb6603ace96f1dc55ea6196122532d HEAD report-status
delete-refs ofs-delta\n
+   S: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe refs/heads/debug\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/master\n
+   S: 003f74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/team\n
+   S: 0000
+
+   C: 003e7d1665144a3a975c05f1f43902ddaf084e784dbe
74730d410fcb6603ace96f1dc55ea6196122532d refs/heads/debug\n
+   C: 003e74730d410fcb6603ace96f1dc55ea6196122532d
5a3f6be755bbb7deae50065988cbfa1ffa9ab68a refs/heads/master\n
+   C: 0000
+   C: [PACKDATA]
+
+   S: 000aunpack ok\n
+   S: 000aok refs/heads/debug\n
+   S: 000ang refs/heads/master non-fast-forward\n
+----
+
diff --git a/Documentation/technical/protocol-capabilities.txt
b/Documentation/technical/protocol-capabilities.txt
new file mode 100644
index 0000000..dad7d16
--- /dev/null
+++ b/Documentation/technical/protocol-capabilities.txt
@@ -0,0 +1,146 @@
+Git Protocol Capabilities
+=========================
+
+On the very first line of the initial server response, the first
+reference is followed by a null byte and then a list of space
+delimited server capabilities.  These allow the server to declare
+what it can and cannot do to the client.
+
+Client sends space separated list of capabilities it wants.  It
+SHOULD send a subset of server capabilities, i.e do not send
+capabilities served does not advertise.  The client SHOULD NOT ask
+for capabilities the server did not say it supports.
+
+Server MUST ignore capabilities it does not understand.  Server MUST
+NOT ignore capabilities that client requested and server advertised.
+
+multi-ack
+---------
+
+The 'multi-ack' capability allows the server to return "ACK $SHA1
+continue" as soon as it finds a commit that it can use as a common
+base, between the client's wants and the client's have set.
+
+By sending this early, the server can potentially head off the client
+from walking any further down that particular branch of the client's
+repository history.  The client may still need to walk down other
+branches, sending have lines for those, until the server has a
+complete cut across the DAG, or the client has said "done".
+
+Without multi_ack, a client sends have lines in --date-order until
+the server has found a common base.  That means the client will send
+have lines that are already known by the server to be common, because
+they overlap in time with another branch that the server hasn't found
+a common base on yet.
+
+The client has things in caps that the server doesn't; server has
+things in lower case.
+
+                         +---- u ---------------------- x
+                        /             +----- y
+                       /             /
+                      a -- b -- c -- d -- E -- F
+                       \
+                        +--- Q -- R -- S
+
+If the client wants x,y and starts out by saying have F,S, the server
+doesn't know what F,S is.  Eventually the client says "have d" and
+the server sends "ACK d continue" to let the client know to stop
+walking down that line (so don't send c-b-a), but its not done yet,
+it needs a base for X. The client keeps going with S-R-Q, until a
+gets reached, at which point the server has a clear base and it all
+ends.
+
+Without multi_ack the client would have sent that c-b-a chain anyway,
+interleaved with S-R-Q.
+
+thin-pack
+---------
+
+Server can send thin packs, i.e. packs which do not contain base
+elements, if those base elements are available on clients side.
+Client requests thin-pack capability when it understands how to "thicken"
+them adding required delta bases making them independent.
+
+Client MUST NOT request 'thin-pack' capability if it
+cannot turn thin packs into proper independent packs.
+
+
+side-band, side-band-64k
+------------------------
+
+This means that server can send, and client understand multiplexed
+(muxed) progress reports and error info interleaved with the packfile
+itself.
+
+These two options are mutually exclusive.  A client should ask for
+only one of them, and a modern client always favors side-band-64k.
+
+The 'side-band' capability allows up to 1000 bytes per packet.  But
+the packet length field is 4 bytes, in hex, so 16 bits worth of
+information space.  Limiting it to only 1000 bytes for a large 800
+MiB binary pack file on initial clone is really quite poor usage of
+the data stream space.
+
+The "side-band-64k" capability came about as a way for newer clients
+that can handle much larger packets to request packets that are
+actually crammed nearly full (65520 bytes), while maintaining
+backward compatibility for the older clients.
+
+The client MUST send only maximum of one of "side-band" and "side-
+band-64k".  Server MUST favor side-band-64k if client requests both.
+
+ofs-delta
+---------
+
+Server can send, and client understand PACKv2 with delta refering to
+its base by position in pack rather than by SHA-1.  Its that they can
+send/read OBJ_OFS_DELTA, aka type 6 in a pack file.
+
+shallow
+-------
+
+Server can send shallow clone (git clone --depth ...).
+
+no-progress
+-----------
+
+The client was started with "git clone -q" or something, and doesn't
+want that side brand 2.  Basically the client just says "I do not
+wish to receive stream 2 on sideband, so do not send it to me, and if
+you did, I will drop it on the floor anyway".  However, the sideband
+channel 3 is still used for error responses.
+
+include-tag
+-----------
+
+The 'include-tag' capability is about sending tags if we are sending
+objects they point to.  If we pack an object to the client, and a tag
+points exactly at that object, we pack the tag too.  In general this
+allows a client to get all new tags when it fetches a branch, in a
+single network connection.
+
+Clients MAY always send include-tag, hardcoding it into a request.
+The decision for a client to request include-tag only has to do with
+the client's desires for tag data, whether or not a server had
+advertised objects in the refs/tags/* namespace.
+
+Clients SHOULD NOT send include-tag if remote.name.tagopt was set to
+--no-tags, as the client doesn't want tag data.
+
+Servers MUST accept include-tag without error or warning, even if the
+server does not understand or support the option.
+
+Servers SHOULD pack the tags if their referrant is packed and the
+client has requested include-tag.
+
+Clients MUST be prepared for the case where a server has ignored
+include-tag and has not actually sent tags in the pack.  In such
+cases the client SHOULD issue a subsequent fetch to acquire the tags
+that include-tag would have otherwise given the client.
+
+The server SHOULD send include-tag, if it supports it, irregardless
+of whether or not there are tags available.
+
+Servers SHOULD support all capabilities defined in this document.
+
diff --git a/Documentation/technical/protocol-common.txt
b/Documentation/technical/protocol-common.txt
new file mode 100644
index 0000000..d28ad98
--- /dev/null
+++ b/Documentation/technical/protocol-common.txt
@@ -0,0 +1,97 @@
+Documentation Common to Pack and Http Protocols
+===============================================
+
+ABNF Notation
+-------------
+
+ABNF notation as described by RFC 5234 is used within the protocol documents,
+except the following replacement core rules are used:
+----
+	HEXDIG    =  DIGIT / "a" / "b" / "c" / "d" / "e" / "f"
+----
+
+We also define the following common rules:
+----
+	NUL       =  %x00
+	zero-id   =  40*"0"
+	obj-id    =  40*(HEXDIGIT)
+
+	refname  =  "HEAD"
+	refname /=  "refs/" <see discussion below>
+----
+
+A refname is a hierarichal octet string beginning with "refs/" and
+not violating the 'git-check-ref-format' command's validation rules.
+More generally, they:
+
+. They can include slash `/` for hierarchical (directory)
+  grouping, but no slash-separated component can begin with a
+  dot `.`.
+
+. They must contain at least one `/`. This enforces the presence of a
+  category like `heads/`, `tags/` etc. but the actual names are not
+  restricted.
+
+. They cannot have two consecutive dots `..` anywhere.
+
+. They cannot have ASCII control characters (i.e. bytes whose
+  values are lower than \040, or \177 `DEL`), space, tilde `~`,
+  caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+  or open bracket `[` anywhere.
+
+. They cannot end with a slash `/` nor a dot `.`.
+
+. They cannot end with the sequence `.lock`.
+
+. They cannot contain a sequence `@{`.
+
+. They cannot contain a `\\`.
+
+
+pkt-line Format
+---------------
+
+Much (but not all) of the payload is described around pkt-lines.
+
+A pkt-line is a variable length binary string.  The first four bytes
+of the line, the pkt-len, indicates the total length of the line,
+in hexadecimal.  The pkt-len includes the 4 bytes used to contain
+the length's hexadecimal representation.
+
+A pkt-line MAY contain binary data, so implementors MUST ensure
+pkt-line parsing/formatting routines are 8-bit clean.
+
+A non-binary line SHOULD BE terminated by an LF, which if present
+MUST be included in the total length.
+
+The maximum length of a pkt-line's data component is 65520 bytes.
+Implementations MUST NOT send pkt-line whose length exceeds 65524
+(65520 bytes of payload + 4 bytes of length data).
+
+Implementations SHOULD NOT send an empty pkt-line ("0004").
+
+A pkt-line with a length field of 0 ("0000"), called a flush-pkt,
+is a special case and MUST be handled differently than an empty
+pkt-line ("0004").
+
+----
+	pkt-line     =  data-pkt / flush-pkt
+
+	data-pkt     =  pkt-len pkt-payload
+    pkt-len      =  4*(HEXDIG)
+	pkt-payload  =  (pkt-len - 4)*(OCTET)
+
+	flush-pkt    = "0000"
+----
+
+Examples (as C-style strings):
+
+----
+  pkt-line          actual value
+  ---------------------------------
+  "0006a\n"         "a\n"
+  "0005a"           "a"
+  "000bfoobar\n"    "foobar\n"
+  "0004"            ""
+----
+
-- 
1.6.5.2.75.gad2f8

^ permalink raw reply related	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2009-11-15  9:12 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-04  5:58 [PATCH] Update packfile transfer protocol documentation Scott Chacon
2009-11-04  6:36 ` Sverre Rabbelier
2009-11-05  5:24 ` Junio C Hamano
     [not found]   ` <20091111171924.6117@nanako3.lavabit.com>
2009-11-11 10:05     ` [PATCH 2/2] pack documentation review updates Scott Chacon
2009-11-15  9:11       ` Junio C Hamano
  -- strict thread matches above, loose matches on Subject: below --
2009-11-01 23:18 [PATCH] Update packfile transfer protocol documentation Scott Chacon
2009-11-02  5:17 ` Junio C Hamano
2009-11-02 15:41   ` Shawn O. Pearce
2009-11-02 17:31     ` Junio C Hamano
2009-11-02 15:43 ` Shawn O. Pearce
2009-11-02 23:48 ` Junio C Hamano
2009-11-02 23:57   ` Shawn O. Pearce
2009-11-03  0:36     ` Junio C Hamano
2009-11-03  0:58       ` Shawn O. Pearce
2009-11-03 22:05         ` Scott Chacon
2009-11-04  0:40           ` Junio C Hamano
2009-11-04  0:40 ` Junio C Hamano
2009-11-04  0:56   ` Shawn O. Pearce
2009-11-04  1:07     ` Junio C Hamano
2009-11-04  1:18       ` Shawn O. Pearce
2009-11-04  1:48         ` Junio C Hamano
2009-10-29 17:35 Scott Chacon
2009-10-30 22:07 ` Junio C Hamano
2009-10-31  2:06 ` Shawn O. Pearce
2009-10-31 20:12   ` Johannes Sixt

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.