Introduction
Git can transport data over four families of protocols. Each has different trade-offs in performance, authentication, and firewall friendliness.
Local / file
Cloning from a directory uses local file I/O. Two URL forms:
git clone /srv/git/widget.git
git clone file:///srv/git/widget.git
The first form may use hardlinks for objects when on the same filesystem (very fast, very space-efficient). The file:// form always copies via the smart protocol.
SSH
The default for authenticated workflows. Uses your SSH client and key:
git clone [email protected]:example/widget.git
git clone ssh://[email protected]/example/widget.git
Behind the scenes, the client invokes ssh and runs git-upload-pack or git-receive-pack on the server side. Configure keys via ~/.ssh/config and ssh-agent.
HTTP / HTTPS
Most firewall-friendly and the default for many hosts:
git clone https://github.com/example/widget.git
The smart HTTP protocol uses POST /info/refs?service=git-upload-pack and similar endpoints. Authentication is via Basic auth (deprecated in many providers) or token in the password field. A credential helper avoids prompts on every operation:
git config --global credential.helper cache
git config --global credential.helper osxkeychain # macOS
git config --global credential.helper manager # Windows
git:// (anonymous)
git clone git://example.com/widget.git
Port 9418, unauthenticated, plaintext. Mostly historical; not recommended for new deployments because it offers no integrity guarantees beyond Git's own hashes.
Protocol versions
The wire protocol has v0, v1, and v2. Protocol v2 (Git 2.18+, default 2.26+) is dramatically faster for repos with many refs, because the server only advertises refs the client asked for.
git -c protocol.version=2 ls-remote origin
git config --global protocol.version 2
Smart vs dumb
"Smart" protocols negotiate; "dumb" HTTP just exposes the .git/ directory. Dumb HTTP requires git update-server-info on every push and is slower; almost no one uses it today.
Choosing a protocol
- HTTPS: easiest to set up, works everywhere, good for read-only and CI.
- SSH: best for daily push/pull when you control your key.
- file://: convenient for local mirrors and tests.
- git://: avoid except for extremely permissive public mirrors.
Capability negotiation
At connection time, client and server exchange capabilities (multi-ack, side-band, ofs-delta, filter, partial clone, push-options, atomic, etc.). Supported capabilities determine which features the operation can use. Inspect with packet tracing:
GIT_TRACE_PACKET=1 git -c protocol.version=2 ls-remote origin 2>&1 | head -40
Older servers may not support newer capabilities; the client falls back gracefully. If you see surprisingly slow clones or fetches, an old server lacking multi-ack-detailed or filter is often the cause.
Common mistakes
Mixing HTTPS and SSH URLs in the same repo; if a CI uses HTTPS but your dev uses SSH, scripts can confuse each other. Either stick to one or use insteadOf rewriting:
git config --global url."[email protected]:".insteadOf "https://github.com/"
Storing personal access tokens in plaintext config; use a credential helper instead. Forgetting to enable protocol.version=2 on old Git installs. Finally, exposing git:// on the open internet for write access; the protocol cannot authenticate. Use SSH or HTTPS.