Home / Alt manpages / gitprotocol-v2(5)

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

Make Git Wire Protocol v2 Predictable

You will finish with Git wire protocol v2 enabled for the scope you choose, a repeatable trace that proves which version was negotiated, and a useful explanation when a remote falls back. The commands below were checked with Git 2.43.0, the installed version on this machine.

Allow about 15 minutes. You need Git and a repository with a reachable remote. The checks are ordinary user commands. Nothing here needs sudo, and no command changes a server or rewrites repository history.

1. Understand what protocol v2 changes

Protocol v2 is a request and response wire format for Git transports. A client first asks for version 2 and receives a capability advertisement. It can then request commands such as ls-refs or fetch. Reference advertisement is no longer automatically bundled into the first exchange, so ls-refs can request the refs the client needs.

This is a transport detail. It does not change your branch names, object IDs, authentication method or repository contents. It also does not guarantee a faster transfer: the server, network and operation still determine that.

Git 2.43.0 documents protocol version 2 as the default when protocol.version is unset. The client falls back to version 0 if the server does not support the requested version. That default is not the same as proof that a particular remote accepted v2, so verify the exchange when it matters.

2. Check the Git version and current setting

Start by recording the client version and any explicit setting:

$ git --version
git version 2.43.0
$ git config --show-origin --get protocol.version

The second command may print nothing. That means no explicit value was found in the normal Git configuration files, not that protocol v2 is unavailable. Ask Git what it would use without changing configuration:

$ git config --get protocol.version || printf '%s
' 'unset; Git default applies'

Checkpoint: keep the version output. A trace from a different Git executable or wrapper can otherwise send you looking at the wrong client.

3. Pin protocol v2 for one operation

Use -c when testing a remote or when one job needs an explicit setting without changing persistent files:

$ git -c protocol.version=2 ls-remote https://git.example.invalid/team/project.git

Replace the URL with a real remote that you are authorised to read. ls-remote asks for references and does not create or update a local branch. It may still contact your credential helper, proxy or server, so do not paste secrets into the URL.

If the server accepts v2, Git uses the protocol's ls-refs command for this operation. If it does not, Git's documented fallback is version 0. A successful command alone does not distinguish those cases.

4. Verify the negotiated version

Enable packet tracing only for this diagnostic command:

$ GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote https://git.example.invalid/team/project.git

Look in the diagnostic output for a server line containing version 2, followed by capabilities such as ls-refs. A local Git 2.43.0 file-transport check produced output shaped like this:

packet:  upload-pack> version 2
packet:  upload-pack> agent=git/2.43.0
packet:  upload-pack> ls-refs=unborn
packet:    ls-remote> command=ls-refs

Trace output can expose ref names, server details and protocol metadata. Treat it as diagnostic data, not as a log to publish or attach without review. It is sent to standard error, while the normal ref listing remains on standard output.

Checkpoint: if you cannot find version 2, do not call the result v2 merely because the command succeeded. Check the remote URL, the selected Git binary, and whether a wrapper or proxy changed the request.

5. Choose a persistent scope

Once the one-operation test works, set the value only where you need it. For every repository, use:

$ git config --global protocol.version 2
$ git config --global --get protocol.version
2

For one repository, omit --global while inside that repository:

$ git config protocol.version 2
$ git config --get protocol.version
2

The repository setting is useful when you are testing a single remote. The global setting affects future operations for your user, including scripts and other repositories, so it is a broader change. It is still a client preference, not a server configuration.

To undo either change, remove the setting at the same scope:

$ git config --global --unset protocol.version

For a repository-local setting, run git config --unset protocol.version there instead. The command returns a non-zero status if no value existed; that is harmless when the setting was already absent. Re-run the command from step 2 to confirm that the intended scope is gone.

6. Account for transport differences

For HTTPS, Git requests v2 through the Git-Protocol: version=2 HTTP header. A Git HTTP backend must pass that request into GIT_PROTOCOL; a reverse proxy or hosting service that drops the header can make a capable client fall back.

For SSH and file transports, the client uses the GIT_PROTOCOL environment variable explicitly. Git normally arranges this for its own transport operations. An SSH server or forced command may need to allow the variable through. Do not add arbitrary environment forwarding to a shared SSH service: review its server policy and trust boundary first.

For the git:// transport, the request carries version=2 as an extra protocol parameter. The server still decides whether it can answer with v2. These transport-specific mechanisms are why copying an HTTP header into an SSH configuration, or vice versa, is not a reliable fix.

7. Troubleshoot a fallback safely

First reproduce the smallest read-only operation with tracing:

$ GIT_TRACE=1 GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote origin

Use origin only if that is the remote name in this repository. Check it with:

$ git remote -v

If the trace shows version 0 or no version 2 advertisement, compare these points:

  • the command is using the Git version you checked, rather than another installation in a service account's PATH;
  • the remote URL uses the transport you think it does;
  • an HTTP proxy, SSH forced command or Git server is not removing the version request;
  • the server is actually new enough and configured to support protocol v2.

Do not force an undocumented capability or edit packet bytes by hand. Unknown capability keys must be ignored by clients, and command requests must use capabilities the server advertised. If fallback is consistent and the operation works, leave it in place while the server owner investigates. If the operation fails, capture the trace after redacting URLs, repository names and credentials, then give it to the remote administrator.

Done means

  • git --version identifies the client you are actually testing.
  • You have selected one-operation, repository-local or global configuration deliberately.
  • A traced ls-remote shows version 2 when the remote accepts v2.
  • You understand that an otherwise successful operation may have fallen back to version 0.
  • Any packet trace is treated as sensitive diagnostic output and reviewed before sharing.