Home / Alt manpages / gitprotocol-capabilities(5)

  • gitprotocol-capabilities(5)
  • File format
  • linux

Read Git Protocol Capabilities Without Guessing

Git's capability advertisement decides what a fetch or push is even allowed to ask for, and most people meet it only once client and server disagree. This walks you through the advertisement used by protocol versions 0 and 1, how to line those capabilities up with fetch or push, and how to trace a packet exchange without changing anything. Allow about fifteen minutes. You need Git and a read-only URL for a repository you are allowed to contact.

The installed reference here is Git 2.43.0 from the git-man package, version 1:2.43.0-1ubuntu7.3. The manual page describes the protocol, not a configuration file you edit directly. Most people only need this when diagnosing a client/server mismatch or writing a Git-compatible server.

1. Confirm the local Git version

Record the version before you compare packet traces or documentation:

$ git --version
git version 2.43.0

Capability details vary between implementations and protocol generations. The installed manual covers v0 and v1 specifically. Protocol v2 has its own negotiation format, documented by gitprotocol-v2, so do not carry this page's packet assumptions over to a v2 trace.

Checkpoint

If your Git reports a different version, keep that fact attached to the trace. The names below come from the installed 2.43.0 manual, and upstream reports no changes to this page since the 2.44.0 documentation revision.

2. Capture a read-only capability advertisement

Use a repository URL you trust that carries no credentials. git ls-remote asks for references without creating or updating a local repository. Packet tracing is diagnostic output, so keep it out of shared logs if the URL could leak anything private.

$ GIT_TRACE_PACKET=1 git ls-remote https://HOST/OWNER/REPOSITORY.git HEAD
... packet trace varies by server and protocol ...
< 0000
< ... reference advertisement ...

The exact trace is server-dependent. In a v0 or v1 advertisement, the first reference in the initial response is followed by a NUL byte, then space-separated capability names, all in the same packet-level exchange. A trace may also show protocol selection or transport diagnostics around it, so do not treat every line as a capability.

Warning

Do not paste a real access token into the URL. If your transport uses a credential helper, leave credentials to that helper, and redact the trace before sending it to anyone else.

3. Separate server offers from client requests

Read the advertisement as an offer, not a command list. A client may only request capabilities the server actually advertised. A server must diagnose and abort on a capability it does not understand, and must never advertise one it cannot honour.

That rule explains a common debugging trap: seeing a capability written up in a document does not mean a particular hosting service, transport or Git version will offer it. Compare the names actually advertised in your trace against the names requested later in the exchange.

The server, for example, may advertise agent=X as an informational version string, and a client may return agent=Y only after the server mentioned the agent capability. These strings are for statistics and debugging. Do not treat them as a programmatic test for whether some other feature exists.

4. Classify a capability by operation

Start with the operation you are diagnosing. The receive-pack process handles pushes, upload-pack handles fetches. The installed manual groups several capabilities by process:

OperationRepresentative capabilitiesPractical meaning
Pushatomic, report-status, report-status-v2, delete-refs, quiet, push-certControls reference update behaviour, status reporting, progress, deletion and signed push certificates.
Fetch and pushofs-delta, side-band-64kControls pack representation or multiplexed pack, progress and error streams.
Usually fetchshallow, filter, include-tag, symrefSupports shallow history, partial transfer, annotated tags or symbolic-reference information.

Treat the table as a working classification, not a complete protocol reference. The manual states that every other capability in this document is recognised only by upload-pack. If a trace concerns a push, do not assume a fetch-only capability can be requested during it.

5. Check the pack-stream choice

Watch side-band and side-band-64k closely when a trace seems to mix progress with pack data. They are mutually exclusive: a client sends only one, and a server must reject a request carrying both. Modern clients favour side-band-64k.

Each multiplexed packet has a pkt-line length, a one-byte stream code and the payload. Stream code 1 carries pack data, code 2 carries progress, code 3 carries a fatal error just before the stream aborts. The documented maximum packet sizes are 1000 bytes for side-band and 65520 bytes for side-band-64k, and the stream-code byte counts as part of each packet.

Do not try to patch a broken stream by enabling both options. Find where the client selected one capability, then compare it against the server advertisement and the implementation on the other side.

6. Treat hash negotiation as its own decision

The object-format capability carries a hash algorithm. It can be advertised more than once, with the first advertised algorithm used for the reference advertisement. When a client sends it, the chosen algorithm must be one the server supports; if it is absent, the manual says to assume SHA-1.

This is not the same thing as an agent string. An agent identifies software for diagnostics; object-format affects the actual object names used for communication. Never infer the hash algorithm from a product version or an agent string.

In the same vein, symref=HEAD:refs/heads/BRANCH describes a symbolic ref. It can help a clone pick its initial branch, but it is not a promise that every advertised reference is a local branch.

7. Handle push-specific safety boundaries

Some capabilities change repository state or open up security-sensitive workflows.

  • atomic: all reference updates in the push happen in one transaction, or none do, which matters when partial success would leave related branches inconsistent.
  • delete-refs: the server accepts a zero object ID as a reference-update target, allowing a reference to be deleted. Treat any deletion request as destructive: review the exact ref and keep a recovery reference or backup before running it. Discovery alone deletes nothing.
  • push-cert=<nonce>: the receive-pack server accepts a signed push certificate and wants that nonce inside it. A client must not send a certificate unless the server advertised the capability, and you should not enable signed-push behaviour just because a server looks like a familiar product.
  • push-options: once advertised and requested, this gets passed to the server's pre-receive and post-receive hooks. Review the server's hook policy before sending any option on a shared or production repository.

8. Diagnose a mismatch without changing state

Compare three things in order: the protocol version, the server's advertisement and the client's request. A name in the request but missing from the advertisement means the client or an intermediary is wrong. A capability the server advertises but cannot actually use means the server is breaking the protocol contract. If the exchange is v2, switch to the v2 documentation before you interpret the packets.

For a reproducible report, save the Git version, transport, endpoint type, whether the operation was fetch or push, and a redacted packet trace. Replace repository names, hostnames, tokens and session identifiers wherever disclosure matters. The session-id capability identifies a process across requests, so treat it as diagnostic data rather than harmless decoration.

There is nothing to undo from the commands in this guide: git ls-remote reads remote references, and packet tracing only observes the exchange. If you move from diagnosis to an actual push, stop, review the exact refs and hook effects, and use your normal backup and change-control procedure first.

Done means

  • Recorded the installed Git version and identified whether the exchange is v0, v1 or v2.
  • Captured a read-only advertisement without putting credentials in the URL.
  • Told server-advertised capabilities apart from client-requested ones.
  • Classified capabilities by fetch, push or shared pack-stream use.
  • Treated ref deletion, push certificates and hook-delivered push options as security-sensitive.
  • Can produce a redacted, reproducible trace without changing repository state.