Read Git Protocol Capabilities Without Guessing
You will inspect the capability advertisement used by Git protocol versions 0 and 1, relate those capabilities to fetch or push, and use packet tracing without changing a repository. Allow about fifteen minutes. You need Git and a read-only URL for a repository you are allowed to contact.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Confirm the local Git version
- 2. Capture a read-only capability advertisement
- 3. Separate server offers from client requests
- 4. Classify a capability by operation
- 5. Check the pack-stream choice
- 6. Treat hash negotiation as a separate decision
- 7. Handle push-specific safety boundaries
- 8. Diagnose a mismatch without changing state
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 that you edit directly. Most users only need this knowledge when diagnosing a client/server mismatch or writing a Git-compatible server.
1. Confirm the local Git version
Record the version before comparing packet traces or documentation:
$ git --version
git version 2.43.0
Capability details can vary between implementations and protocol generations. The installed manual is specifically about v0 and v1. Protocol v2 has a separate negotiation format and is documented by gitprotocol-v2, so do not apply this page's packet assumptions to a v2 trace.
Checkpoint: if your Git reports a different version, keep that fact with the trace. The names below are taken from the installed 2.43.0 manual and the current upstream documentation reports no changes to this page after the 2.44.0 documentation revision.
2. Capture a read-only capability advertisement
Use a repository URL that you trust and that does not contain 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 expose private information.
$ 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 on the initial response is followed by a NUL byte and then space-separated capability names. The reference and capability list arrive together in that packet-level exchange. A trace may also show protocol selection or transport diagnostics around it, so do not treat every line as a capability.
Do not paste a real access token into the URL. If your transport uses a credential helper, leave credentials to that helper. Stop and redact the trace before sending it to someone else.
3. Separate server offers from client requests
Read the advertisement as an offer, not as a command list. The client may request only capabilities the server advertised. A server must diagnose and abort when it receives a capability it does not understand, and it must not advertise a capability it cannot honour.
That rule explains a common debugging trap: seeing a capability in a document does not mean that a particular hosting service, transport or Git version will offer it. Compare the names actually advertised in your trace with the names requested later in the exchange.
For example, the server may advertise agent=X as an informational version string. A client may return agent=Y only after the server mentioned the agent capability. These strings are for statistics and debugging. Do not use them as a programmatic test for whether another feature exists.
4. Classify a capability by operation
Start with the operation being diagnosed. The receive-pack process handles pushes, while upload-pack handles fetches. The installed manual groups several capabilities by process:
| Operation | Representative capabilities | Practical meaning |
|---|---|---|
| Push | atomic, report-status, report-status-v2, delete-refs, quiet, push-cert | Controls reference update behaviour, status reporting, progress, deletion and signed push certificates. |
| Fetch and push | ofs-delta, side-band-64k | Controls pack representation or multiplexed pack, progress and error streams. |
| Usually fetch | shallow, filter, include-tag, symref | Supports shallow history, partial transfer, annotated tags or symbolic-reference information. |
The table is a working classification, not a complete protocol reference. The manual says that all other capabilities in this document are recognised only by upload-pack. If a trace concerns a push, do not assume that a fetch-only capability can be requested during that push.
5. Check the pack-stream choice
Pay particular attention to side-band and side-band-64k when a trace appears to mix progress with pack data. They are mutually exclusive. A client must send only one, and the server must reject a request containing 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, and 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; the stream-code byte is part of each packet.
Do not try to repair a stream by enabling both options. Find the point where the client selected one capability, then compare it with the server advertisement and the protocol implementation on the other side.
6. Treat hash negotiation as a separate decision
The object-format capability carries a hash algorithm. It may 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 as an agent string. An agent identifies software for diagnostics; object-format affects the object names used for communication. Never infer the hash algorithm from a product version or from an agent string.
Similarly, symref=HEAD:refs/heads/BRANCH describes a symbolic ref. It can help a clone choose 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 expose security-sensitive workflows. If a server advertises atomic and the client requests it, all reference updates happen in one transaction or none do. This is useful when partial success would leave related branches inconsistent.
delete-refs means the server accepts a zero object ID as the target of a reference update, allowing a reference to be deleted. Treat any operation that requests deletion as destructive: review the exact ref and keep a recovery reference or backup before running it. Capability discovery itself does not delete anything.
push-cert=<nonce> means the receive-pack server is willing to accept a signed push certificate and asks for that nonce in the certificate. A client must not send a push certificate unless the server advertised the capability. Do not enable signed-push behaviour merely because a server identifies itself as a familiar product.
Push options are another boundary. When push-options is advertised and requested, the server passes the options to its pre-receive and post-receive hooks. Review the server's hook policy before sending any option, especially 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. If the request contains a name absent from the advertisement, the client or an intermediary is wrong. If the server advertises a capability that it cannot use, the server is violating the protocol contract. If the exchange is v2, switch to the v2 documentation before interpreting 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 where disclosure matters. The session-id capability is intended to identify a process across requests, so it should be treated 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 observes the exchange. If you move from diagnosis to a real push, stop, review the exact refs and hook effects, and use your normal backup and change-control procedure first.
Done means
- You recorded the installed Git version and identified whether the exchange is v0, v1 or v2.
- You captured a read-only advertisement without putting credentials in the URL.
- You distinguished server-advertised capabilities from client-requested capabilities.
- You classified capabilities by fetch, push or shared pack-stream use.
- You treated reference deletion, push certificates and hook-delivered push options as security-sensitive.
- You can provide a redacted, reproducible trace without changing repository state.