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, and disconnect, when it does not need any pack
data. This can happen with the ls-remote command, and also can happen when
the client already is up to date.
Otherwise, it enters the negotiation phase, where the client and
server determine what the minimal packfile necessary for transport is,
by telling the server what objects it wants, its shallow objects
(if any), and the maximum commit depth it wants (if any). The client
will also send a list of the capabilities it wants to be in effect,
out of what the server said it could do with the first want line.
upload-request = want-list
*shallow-line
*1depth-request
[filter-request]
flush-pkt
want-list = first-want
*additional-want
shallow-line = PKT-LINE("shallow" SP obj-id)
depth-request = PKT-LINE("deepen" SP depth) /
PKT-LINE("deepen-since" SP timestamp) /
PKT-LINE("deepen-not" SP ref)
first-want = PKT-LINE("want" SP obj-id SP capability-list)
additional-want = PKT-LINE("want" SP obj-id)
depth = 1*DIGIT
filter-request = PKT-LINE("filter" SP filter-spec)
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.
The client MUST write all obj-ids which it only has shallow copies
of (meaning that it does not have the parents of a commit) as
shallow lines so that the server is aware of the limitations of
the client’s history.
The client now sends the maximum commit history depth it wants for
this transaction, which is the number of commits it wants from the
tip of the history, if any, as a deepen line. A depth of 0 is the
same as not making a depth request. The client does not want to receive
any commits beyond this depth, nor does it want objects needed only to
complete those commits. Commits whose parents are not received as a
result are defined as shallow and marked as such in the server. This
information is sent back to the client in the next step.
The client can optionally request that pack-objects omit various
objects from the packfile using one of several filtering techniques.
These are intended for use with partial clone and partial fetch
operations. An object that does not meet a filter-spec value is
omitted unless explicitly requested in a want line. See rev-list
for possible filter-spec values.
Once all the want’s and 'shallow’s (and optional 'deepen) are
transferred, clients MUST send a flush-pkt, to tell the server side
that it is done sending the list.
Otherwise, if the client sent a positive depth request, the server
will determine which commits will and will not be shallow and
send this information to the client. If the client did not request
a positive depth, this step is skipped.
shallow-update = *shallow-line
*unshallow-line
flush-pkt
shallow-line = PKT-LINE("shallow" SP obj-id)
unshallow-line = PKT-LINE("unshallow" SP obj-id)
If the client has requested a positive depth, the server will compute
the set of commits which are no deeper than the desired depth. The set
of commits starts at the client’s wants.
The server writes shallow lines for each
commit whose parents will not be sent as a result. The server writes
an unshallow line for each commit which the client has indicated is
shallow, but is no longer shallow at the currently requested depth
(that is, its parents will now be sent). The server MUST NOT mark
as unshallow anything which the client has not indicated was shallow.
Now the client will send a list of the obj-ids it has using have
lines, so the server can make a packfile that only contains the objects
that the client needs. 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.
upload-haves = have-list
compute-end
have-list = *have-line
have-line = PKT-LINE("have" SP obj-id)
compute-end = flush-pkt / PKT-LINE("done")
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
chosen by the client.
-
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 NAK and then wait for another response
from the client - either a done or another list of have lines.
In multi_ack_detailed mode:
Without either multi_ack or multi_ack_detailed:
-
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, it’s 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 of its objects), then the client will send
a done command. The done command signals to the server that the client
is ready to receive its 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. obj-id is the object
name of the last commit determined to be common. 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.
Instead of ACK or NAK, the server may send an error message (for
example, if it does not recognize an object in a want line received
from the client).
Then the server will start sending its packfile data.
server-response = *ack_multi ack / nak
ack_multi = PKT-LINE("ACK" SP obj-id ack_status)
ack_status = "continue" / "common" / "ready"
ack = PKT-LINE("ACK" SP obj-id)
nak = PKT-LINE("NAK")
A simple clone may look like this (with no have lines):
C: 0054want 74730d410fcb6603ace96f1dc55ea6196122532d multi_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 multi_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: 0031ACK 74730d410fcb6603ace96f1dc55ea6196122532d\n
S: [PACKFILE]