What is Git's wire protocol v2, and what does it change about fetching?
answer
- The old protocol talked first, and said everything
- Ref advertisement was the fixed cost
- The client now asks for prefixes
- One env var over SSH, one header over HTTP
- Trace the packets to see which version ran
basics
~20 sProtocol v2 is Git's second-generation transfer protocol. Instead of the server advertising every ref up front, the client requests only the refs it cares about via ls-refs with ref prefixes, which makes fetches on ref-heavy repositories dramatically cheaper.
solid answer
~50 sIn the original protocol the server opens every connection by advertising **all** refs, so a repository with hundreds of thousands of branches and tags sends a huge list before the client can say what it wants. Protocol v2 replaces that with a command-oriented conversation: the server states its capabilities, and the client issues commands such as `ls-refs` with `ref-prefix` arguments to ask about only the refs it needs, then `fetch`. It is the default for fetches in recent Git and can be forced or disabled with the `protocol.version` config. The version is requested per transport: over HTTP via the `Git-Protocol` header, and over SSH by passing the `GIT_PROTOCOL` environment variable to the server. It was also designed to be extensible, so new server-side capabilities can be added without breaking older clients. `GIT_TRACE_PACKET=1` shows which version a connection actually used.
code
bash · 6 linesGIT_TRACE_PACKET=1 git ls-remote https://example.com/acme/app.git 2>&1 | head -5
# packet: git< version 2
# packet: git< ls-refs=unborn
# packet: git< fetch=shallow wait-for-done
git -c protocol.version=0 ls-remote https://example.com/acme/app.gitgo deeper
Know that Git negotiates a protocol version with the server and that modern Git defaults to version 2; you are unlikely to be asked more at this stage.
Explain the ref-advertisement problem v0 had and how ls-refs with ref prefixes fixes it, plus where the version preference is configured.
Be able to prove which version a given endpoint negotiated using packet tracing, and explain why a fetch on a ref-heavy repository is slow when it falls back to v0.
Frame it as a fleet-level cost question: on repositories with enormous ref namespaces, routine fetch overhead multiplied by every developer and every CI job is a real budget line.
## What was wrong with v0 Git's original transfer protocol begins every connection with a **ref advertisement**: before any negotiation, the server sends the name and object ID of every ref it has. For a small repository this is invisible. For a repository with a very large number of refs — long-lived projects, automation that creates a ref per change, mirrors of many forks — the advertisement alone can be megabytes, sent in full even when the client only wants to know whether one branch moved. The protocol also had no room to grow: capabilities were squeezed into the first advertisement line, and adding features risked confusing existing clients. ## What v2 changes Protocol v2 restructures the conversation into commands. After connecting, the server announces which commands and capabilities it supports. The client then issues them explicitly: - `ls-refs` — ask about refs, optionally narrowed with `ref-prefix` arguments so the server only returns matching refs. - `fetch` — negotiate and receive a packfile. The practical effect is that `git fetch origin main` no longer needs the entire ref namespace to travel. On ref-heavy repositories this can turn the dominant cost of a routine fetch into a rounding error. The second effect is extensibility: because capabilities are advertised in a structured way, servers can add features and clients can ignore what they do not understand. ## How the version gets requested Protocol version selection is per transport, and the client always asks — it cannot be imposed unilaterally, since the server may only speak v0: - **HTTP**: the client sends a `Git-Protocol` request header. - **SSH**: the client passes the `GIT_PROTOCOL` environment variable through to the server. SSH servers only forward environment variables they are configured to accept, which is why an SSH endpoint can silently stay on v0 while the same host's HTTPS endpoint uses v2. - **Local and daemon transports** have their own equivalents. The client's preference is `protocol.version` in config; recent Git defaults it to 2 for fetches and falls back automatically when the server does not answer in v2. ## Observing and debugging it `GIT_TRACE_PACKET=1 git ls-remote <url>` prints the packet-level conversation, including the version line and whether `ls-refs` was used. This is the reliable way to answer "is this host actually giving me v2?" rather than assuming from the client version. `GIT_TRACE=1` gives a coarser view of what Git executed. ## What it does not change Protocol v2 is about the *conversation*, not about authentication, encryption, or object storage. It does not change how you log in, does not alter the packfile format, and does not by itself make an object transfer smaller — the packfile for a given fetch is the same. It removes the fixed overhead of the ref advertisement and provides a place for future capabilities to be negotiated. ## Why interviewers ask It is a good probe for whether a candidate has ever looked below the porcelain at what a fetch actually exchanges. The expected answer is not implementation detail but the shape of the improvement: stop sending everything the server has before the client has said what it wants.
- Why might one host serve protocol v2 over HTTPS but v0 over SSH?Over SSH the version is requested by passing the `GIT_PROTOCOL` environment variable to the server, and SSH servers only forward environment variables they are configured to accept. If that is not permitted, the request never reaches the Git process and the connection falls back to v0, while the HTTPS endpoint — which uses a request header — is unaffected.
- Does protocol v2 make the transferred packfile smaller?No. The negotiation determines which objects are needed, and the packfile for a given set of objects is unchanged. What v2 removes is the fixed overhead of advertising every ref before the client speaks, which is why the benefit is concentrated in repositories with very many refs rather than very large ones.
saying these in an interview costs you the question
- Says v2 compresses objects better than v0
- Thinks v2 changes how authentication works
- Assumes the client can force v2 regardless of the server
- Confuses the ref advertisement with the packfile transfer
- Believes protocol version is a server-only setting