Home / Alt manpages / git-remote-fd(1)

  • git-remote-fd(1)
  • User command
  • linux

Use Git's fd:: Transport When a Script Owns the Connection

git-remote-fd points git fetch, git push or git archive at a socket or pipe pair a supervisor already opened, skipping a new connection.

This is not a general-purpose remote; it is for programs that already own the connection. The examples match the installed Git 2.43.0 manpage, from git-man package version 1:2.43.0-1ubuntu7.3.

Allow about fifteen minutes if you already have a supervising process. You need Git and a process that owns the relevant descriptors. This guide does not create a network connection, start git-upload-pack, or change a repository. There is no elevated-privilege step.

1. Check the local Git contract

Start by confirming your Git version and reading the installed helper documentation. Both are ordinary, read-only commands:

$ git --version
git version 2.43.0
$ man git-remote-fd

The helper is for programs and scripts calling Git, not a replacement for an ordinary SSH or HTTPS remote. Its URL begins with fd:: and names an already-open descriptor.

Checkpoint

If your design does not already have a socket or a pair of pipes connected to the remote Git service, stop here. git-remote-fd cannot discover or open the service for you.

2. Choose the descriptor form

Use one descriptor when it is a bidirectional socket. The number is the file descriptor as seen by the Git process:

fd::17

Use two descriptors when the connection is a pair of separate pipes. The first is the inbound pipe Git reads, the second is the outbound pipe Git writes:

fd::7,8

Do not swap the pair because the numbers look more convenient. With the two-descriptor form, infd is data coming into Git and outfd is data Git sends out. Both descriptors must already be inherited by the Git process or handed to it through your supervisor's normal descriptor-passing mechanism. The URL does not open descriptor 17, 7 or 8, and it cannot make a closed descriptor valid.

3. Account for the completed handshake

The helper assumes the transport handshake already happened before Git starts using it. For a Git protocol that needs a service request, your supervising program must perform that exchange first. Starting Git against an unprepared stream can look exactly like a Git protocol failure even when the descriptor numbers are correct.

  • The supervisor opens the socket or pipes and performs any required preliminary exchange.
  • Git consumes and produces the smart transport stream through the descriptors, nothing more.
  • git-remote-fd reflects that stream. It does not negotiate a new connection.

Checkpoint

Before invoking Git, verify in the supervisor itself that each descriptor is open, connected to the intended service, and positioned where Git should begin. Do this in the supervisor's own diagnostics; the helper has no URL-based fallback.

4. Use a descriptor in a Git operation

For a fetch, pass the descriptor URL where Git expects a remote URL, then name the refspec or branch:

$ git fetch fd::17 master

This fetches master through the bidirectional socket on descriptor 17. It only works when the Git process genuinely has descriptor 17 open and the peer is speaking the expected Git service protocol.

For a push using separate pipes, give both numbers:

$ git push fd::7,8 master

Here Git reads responses from descriptor 7 and writes requests to descriptor 8. The local repository and the remote service still decide whether the ref update is accepted: a working descriptor setup does not grant permission to update a remote branch.

The same URL form works anywhere Git accepts a remote URL, including git archive. Use whatever descriptor arrangement that operation and its remote service require.

5. Add a display hint without changing the connection

You can append a slash and any string to make a descriptor URL clearer when a command or log displays it:

$ git fetch fd::17/build-cache master
$ git push fd::7,8/release master

The text after the slash is ignored by the helper. It is a label for people, not a path, repository name or extra protocol argument, so changing /build-cache to something else does not select a different service.

Warning

Do not put secrets in this hint. A displayed URL can be copied straight into logs, error reports or process diagnostics.

6. Turn on focused diagnostics

When the stream does not behave, set GIT_TRANSLOOP_DEBUG for that one command:

$ GIT_TRANSLOOP_DEBUG=1 git fetch fd::17/build-cache master

The helper prints debugging information about reads and writes. Exact lines depend on what the peer sends, so treat this as a trace rather than a stable output format. Keep the trace private: transport data and protocol details can reveal repository or deployment information.

If the trace shows no useful exchange, check the descriptor inheritance and the completed handshake first. If it shows reads and writes followed by a Git error, investigate the remote service, the requested ref and the protocol data rather than changing descriptor numbers at random.

Common traps

  • Bad descriptor. Git cannot use a number that was closed, not inherited, or allocated differently in the child process. Log the descriptor table at the point where Git is launched.
  • Reversed pipes. If Git reads from the pipe it should write, the operation can block or fail with protocol noise. Recheck the supervisor's read and write ends.
  • Handshake repeated or omitted. The helper expects the preliminary work to be complete already. Coordinate ownership of the first bytes on the stream.
  • Label treated as configuration. Text after the slash is ignored: it cannot repair a wrong descriptor or choose a repository.
  • Debugging treated as success. A trace proves activity, not a successful fetch or push. Check Git's exit status and the operation's actual result.

Recovery

There is no undo command for these examples because the helper itself changes no persistent configuration. If a push did update a remote ref, recover it with your normal Git branch and remote recovery procedure; closing the descriptors does not undo a completed ref update.

Done means

  • You know the connection shape. One bidirectional socket, or two directional pipes.
  • The descriptors are open and inherited by the Git process.
  • Any required transport handshake is complete before Git starts.
  • Your URL uses fd::infd or fd::infd,outfd, with an optional display hint only.
  • A fetch, push or archive returns the result you expected, with GIT_TRANSLOOP_DEBUG available for a private trace.