protocol-v2 Git Command Guide
The Git protocol version 2 is the modern stateless protocol that improves upon version 1 with better performance, cleaner architecture, and enhanced capabilities. It separates concerns and enables more efficient Git operations across all transports.
Protocol V2 Architecture:
Section titled “Protocol V2 Architecture:”Stateless Design:
Section titled “Stateless Design:”Protocol V2 Characteristics:├── Stateless: No server-side state between requests├── Command-based: Explicit command structure├── Capability-driven: Feature negotiation├── Transport-agnostic: Works over any transport└── Extensible: Easy to add new commands/features
Advantages over V1:├── Better performance for large repositories├── Cleaner separation of concerns├── Improved error handling├── Enhanced security features└── Future extensibilityCommand Structure:
Section titled “Command Structure:”V2 Protocol Flow:1. Client → Server: command request2. Server → Client: capability advertisement3. Client → Server: command parameters4. Server → Client: command response5. Connection closes (stateless)Core Commands:
Section titled “Core Commands:”Essential V2 Commands:├── ls-refs: List and filter references├── fetch: Fetch objects and references├── push: Send objects and update references├── clone: Initial repository cloning└── bundle-uri: CDN-based content deliveryProtocol V2 Capabilities:
Section titled “Protocol V2 Capabilities:”Reference Management:
Section titled “Reference Management:”ls-refs Capabilities:├── symrefs: Symbolic reference support├── ref-in-want: References in want lines├── allow-tip-sha1-in-want: SHA-1 in want lines├── allow-reachable-sha1-in-want: Reachable SHA-1 in want└── ref-prefix: Reference prefix filteringFetch Capabilities:
Section titled “Fetch Capabilities:”fetch Capabilities:├── multi_ack_detailed: Detailed ACK responses├── no-done: Skip 'done' packet├── thin-pack: Thin pack support├── side-band: Progress reporting├── side-band-64k: 64KB side-band├── ofs-delta: Offset delta support├── shallow: Shallow fetch support├── deepen-since: Time-based deepening├── deepen-not: Reference-based deepening├── deepen-relative: Relative deepening├── filter: Object filtering└── bundle-uri: Bundle URI supportPush Capabilities:
Section titled “Push Capabilities:”push Capabilities:├── report-status: Operation status reporting├── report-status-v2: Enhanced status reporting├── delete-refs: Reference deletion├── atomic: Atomic reference updates├── object-format: Object format specification├── allow-tip-sha1-in-refspec: SHA-1 in refspecs└── allow-reachable-sha1-in-refspec: Reachable SHA-1 in refspecsAdvanced Capabilities:
Section titled “Advanced Capabilities:”Extended Capabilities:├── server-option: Server option support├── object-info: Object information queries├── session-id: Session identification├── bundle-uri: Bundle URI support├── packfile-uris: Pack file URI support└── wait-for-done: Asynchronous operation supportCommand Implementation:
Section titled “Command Implementation:”ls-refs Command:
Section titled “ls-refs Command:”# List references with filteringClient Request:command=ls-refsobject-format=sha1ref-prefix refs/heads/ref-prefix refs/tags/
Server Response:<reference-advertisement><symref-advertisement><capability-advertisement>fetch Command:
Section titled “fetch Command:”# Fetch with filtering and optimizationClient Request:command=fetchobject-format=sha1want <sha1>want <sha1>have <sha1>filter blob:limit=1mdone
Server Response:<acknowledgments><packfile-data>push Command:
Section titled “push Command:”# Push with status reportingClient Request:command=pushobject-format=sha1oldref <ref> <sha1>newref <ref> <sha1>
Server Response:<status-reports><command-status>Configuration and Usage:
Section titled “Configuration and Usage:”Enabling Protocol V2:
Section titled “Enabling Protocol V2:”# Force protocol version 2git config --global protocol.version 2
# Per-remote configurationgit config remote.origin.protocol version=2
# Environment variableexport GIT_PROTOCOL=version=2Server Configuration:
Section titled “Server Configuration:”# Enable V2 on servergit config --global uploadpack.allowFilter truegit config --global uploadpack.allowAnySHA1InWant truegit config --global receive.advertisePushOptions true
# Configure capabilitiesgit config --global uploadpack.allowRefInWant truegit config --global uploadpack.allowTipSHA1InWant trueClient Configuration:
Section titled “Client Configuration:”# Configure V2 preferencesgit config --global fetch.writeCommitGraph truegit config --global fetch.bundleURI true
# Enable filteringgit config --global fetch.negotiateAlgorithm skipping
# Configure push optionsgit config --global push.useForceIfIncludes truePerformance Optimizations:
Section titled “Performance Optimizations:”Fetch Optimizations:
Section titled “Fetch Optimizations:”# Enable commit graph for faster traversalgit commit-graph write --reachable
# Use bundle URIs for faster clones# Server advertises bundle URIs for CDN delivery
# Enable partial clonesgit clone --filter=blob:limit=1m <url>
# Use shallow clonesgit clone --depth=1 <url>Push Optimizations:
Section titled “Push Optimizations:”# Use atomic pushesgit push --atomic origin main feature
# Enable force-with-leasegit push --force-with-lease origin main
# Use push optionsgit push -o ci.skip origin mainConnection Optimizations:
Section titled “Connection Optimizations:”# Enable protocol V2git config protocol.version 2
# Configure connection reusegit config http.maxRequests 100
# Enable compressiongit config core.compression 9Advanced Features:
Section titled “Advanced Features:”Object Filtering:
Section titled “Object Filtering:”# Blob size filteringgit clone --filter=blob:limit=1m <url>
# Tree filteringgit clone --filter=tree:depth=1 <url>
# Combined filteringgit clone --filter=combine:blob:limit=1m+tree:depth=1 <url>Bundle URIs:
Section titled “Bundle URIs:”# Server advertises bundle locations# Client can download from CDNs
# Configure bundle URIgit config --global fetch.bundleURI true
# Manual bundle usagegit bundle create my.bundle --allgit clone my.bundleAsynchronous Operations:
Section titled “Asynchronous Operations:”# Wait-for-done capability# Server can process operations asynchronously
# Client requests async operationcommand=fetchwait-for-done
# Server acknowledges and processes# Client can disconnect and reconnect laterDebugging Protocol V2:
Section titled “Debugging Protocol V2:”Tracing V2 Operations:
Section titled “Tracing V2 Operations:”# Enable protocol tracingGIT_TRACE=1 git fetch origin
# Trace packet exchangeGIT_TRACE_PACKET=1 git clone <url>
# Debug capability negotiationGIT_TRACE=2 git push origin mainCapability Analysis:
Section titled “Capability Analysis:”# Check server capabilitiesgit ls-remote --upload-pack="git upload-pack --advertise-capabilities" <url>
# Test V2 supportcurl -s "https://github.com/user/repo.git/info/refs?service=git-upload-pack" | head -10
# Force V2 usageGIT_PROTOCOL=version=2 git clone <url>Performance Monitoring:
Section titled “Performance Monitoring:”# Monitor V2 performancetime git clone --depth=1 <url>
# Check protocol versiongit config protocol.version
# Analyze fetch performanceGIT_TRACE_PERFORMANCE=1 git fetch originServer Implementation:
Section titled “Server Implementation:”Basic V2 Server:
Section titled “Basic V2 Server:”#!/bin/bash# Basic Git protocol V2 server
handle_v2_request() { local service="$1" local repo_path="$2"
# Read client request read -r line
# Parse command if [[ "$line" == "command="* ]]; then command="${line#command=}"
case "$command" in "ls-refs") handle_ls_refs "$repo_path" ;; "fetch") handle_fetch "$repo_path" ;; "push") handle_push "$repo_path" ;; *) echo "ERR unknown command '$command'" ;; esac else echo "ERR invalid request format" fi}
handle_ls_refs() { local repo="$1"
# Advertise capabilities echo "version 2" echo "capability-advertisement" echo "ls-refs" echo "fetch" echo "server-option" echo ""
# Send reference list git -C "$repo" for-each-ref --format="%(refname) %(objectname)"}
handle_fetch() { local repo="$1"
# Read fetch parameters while read -r line; do case "$line" in "want "*) wants+=("${line#want }") ;; "have "*) haves+=("${line#have }") ;; "done") break ;; esac done
# Perform fetch negotiation # Send pack data git -C "$repo" upload-pack --stateless-rpc}
# Usagehandle_v2_request "upload-pack" "/path/to/repo.git"Advanced V2 Server Features:
Section titled “Advanced V2 Server Features:”# Server with filtering supporthandle_fetch_with_filter() { local repo="$1"
# Parse filter options while read -r line; do case "$line" in "filter "*) filter="${line#filter }" ;; "want "*) # Apply filter to wanted objects ;; esac done
# Generate filtered pack case "$filter" in "blob:limit="*) limit="${filter#blob:limit=}" # Generate pack with blob size filtering ;; "tree:depth="*) depth="${filter#tree:depth=}" # Generate pack with tree depth filtering ;; esac}
# Server with bundle URI supportadvertise_bundle_uris() { echo "bundle-uri=https://cdn.example.com/bundle.bundle" echo "bundle-uri=https://backup.example.com/bundle.bundle"}
# Server with session trackingtrack_sessions() { local session_id="$1"
# Log session activity echo "$(date): Session $session_id - $command" >> session.log
# Implement session-based optimizations # Cache results, track user patterns, etc.}Migration and Compatibility:
Section titled “Migration and Compatibility:”Migrating from V1 to V2:
Section titled “Migrating from V1 to V2:”# Gradual migration strategymigration_strategy() { echo "Migrating from Git protocol V1 to V2"
# Phase 1: Enable V2 alongside V1 git config --global protocol.version 2
# Phase 2: Test V2 compatibility test_v2_compatibility
# Phase 3: Monitor performance improvements monitor_v2_performance
# Phase 4: Full migration enforce_v2_usage}
test_v2_compatibility() { # Test basic operations git ls-remote <url> git fetch origin git push origin main
# Check for V2-specific features git clone --filter=blob:limit=1m <url>}
monitor_v2_performance() { # Compare V1 vs V2 performance echo "Testing V1 performance:" time GIT_PROTOCOL=version=1 git clone --depth=1 <url> v1-repo
echo "Testing V2 performance:" time GIT_PROTOCOL=version=2 git clone --depth=1 <url> v2-repo}
enforce_v2_usage() { # Force V2 usage git config --global protocol.version 2
# Update server configurations # Disable V1 support if desired}Compatibility Considerations:
Section titled “Compatibility Considerations:”# Handle mixed client versionsserver_compatibility_handler() { # Detect client protocol version if client_supports_v2; then use_protocol_v2 else fallback_to_v1 fi}
client_supports_v2() { # Test V2 support git ls-remote --upload-pack="git upload-pack --advertise-capabilities" <url> | grep -q "version 2"}
# Backward compatibilitylegacy_v1_support() { # Maintain V1 support for older clients git config uploadpack.allowFilter false git config uploadpack.allowAnySHA1InWant false}Security Enhancements:
Section titled “Security Enhancements:”Access Control:
Section titled “Access Control:”# V2-specific security featuresv2_security_features() { # Reference-based access control # Object filtering for security # Session-based authentication # Audit logging improvements}
# Implement V2-aware access controlcheck_v2_permissions() { local command="$1" local user="$2" local repo="$3"
case "$command" in "ls-refs") # Check read permissions ;; "fetch") # Check fetch permissions ;; "push") # Check push permissions ;; esac}Audit and Monitoring:
Section titled “Audit and Monitoring:”# Enhanced V2 audit loggingv2_audit_logging() { local session_id="$1" local command="$2" local user="$3"
# Log V2-specific information echo "$(date): V2 $session_id $user $command" >> audit.log
# Track capabilities used # Monitor performance metrics # Log security events}Troubleshooting V2 Issues:
Section titled “Troubleshooting V2 Issues:”Common V2 Problems:
Section titled “Common V2 Problems:”# V2 not supported by serverGIT_PROTOCOL=version=1 git clone <url>
# Capability negotiation failuresgit config protocol.version 1 # Temporary fallback
# Filter not supportedgit clone --no-filter <url>
# Bundle URI issuesgit config fetch.bundleURI falseDebugging V2 Operations:
Section titled “Debugging V2 Operations:”# Enable detailed tracingGIT_TRACE=2 GIT_TRACE_PACKET=1 git fetch origin
# Check server V2 supportcurl -s "https://github.com/user/repo.git/info/refs?service=git-upload-pack" | grep "version 2"
# Test V2 commands manuallyecho -e "command=ls-refs\nobject-format=sha1\n" | git upload-pack --stateless-rpc <url>Performance Issues:
Section titled “Performance Issues:”# V2 slower than expectedGIT_PROTOCOL=version=1 git clone <url> # Compare
# Disable V2 features for troubleshootinggit config protocol.version 1
# Check network issuesping github.comtraceroute github.comReal-World Usage Examples:
Section titled “Real-World Usage Examples:”Enterprise V2 Deployment:
Section titled “Enterprise V2 Deployment:”#!/bin/bash# Enterprise Git protocol V2 deployment
enterprise_v2_deployment() { local git_server="$1"
echo "Deploying Git protocol V2 on $git_server"
# Configure server for V2 ssh "$git_server" << 'EOF'# Enable V2 capabilitiesgit config --global uploadpack.allowFilter truegit config --global uploadpack.allowAnySHA1InWant truegit config --global receive.advertisePushOptions true
# Configure V2-specific settingsgit config --global uploadpack.allowRefInWant truegit config --global uploadpack.allowTipSHA1InWant true
# Enable bundle URIs for performancegit config --global uploadpack.bundleURI true
# Set up monitoringgit config --global uploadpack.statelessRPC trueEOF
# Test V2 functionality test_v2_server "$git_server"
# Configure clients configure_v2_clients
# Set up monitoring setup_v2_monitoring "$git_server"}
test_v2_server() { local server="$1"
echo "Testing V2 server functionality..."
# Test basic V2 operations git ls-remote "git@$server:test-repo.git"
# Test filtering git clone --filter=blob:limit=1m "git@$server:test-repo.git" filtered-clone
# Test bundle URIs git clone --bundle-uri "git@$server:test-repo.git" bundle-clone
echo "V2 server tests completed"}
configure_v2_clients() { echo "Configuring clients for V2..."
# Global V2 configuration git config --global protocol.version 2 git config --global fetch.writeCommitGraph true git config --global fetch.bundleURI true
# Configure filtering preferences git config --global fetch.negotiateAlgorithm skipping
echo "Client configuration completed"}
setup_v2_monitoring() { local server="$1"
echo "Setting up V2 monitoring..."
# Server-side monitoring ssh "$server" << 'EOF'# Install monitoring scriptcat > /opt/git-monitor.sh << 'MONITOR_EOF'#!/bin/bash# Git V2 monitoring script
while true; do # Count active V2 connections v2_connections=$(netstat -tn | grep :9418 | wc -l)
# Log V2 usage echo "$(date): V2 connections: $v2_connections" >> /var/log/git-v2.log
# Monitor performance git_processes=$(pgrep -f "git.*upload-pack" | wc -l) echo "$(date): Git processes: $git_processes" >> /var/log/git-v2.log
sleep 60doneMONITOR_EOF
chmod +x /opt/git-monitor.shEOF
echo "V2 monitoring setup completed"}
enterprise_v2_deployment "git.company.com"CI/CD V2 Optimization:
Section titled “CI/CD V2 Optimization:”# Optimize CI/CD pipelines with V2ci_v2_optimization() { echo "Optimizing CI/CD for Git protocol V2..."
# Configure V2 for CI git config --global protocol.version 2
# Enable shallow clones for faster builds export GIT_SHALLOW=true
# Configure fetch optimizations git config --global fetch.prune true git config --global fetch.writeCommitGraph true git config --global fetch.bundleURI true
# Use partial clones for large repos git clone --filter=blob:limit=1m <url> repo
# Optimize for CI patterns git config --global gc.autoDetach false git config --global feature.experimental true
# Configure push optimizations git config --global push.useForceIfIncludes true git config --global push.negotiate true
echo "CI/CD V2 optimization completed"}
ci_v2_optimizationCustom V2 Server Implementation:
Section titled “Custom V2 Server Implementation:”#!/bin/bash# Complete Git protocol V2 server implementation
GIT_V2_SERVER_VERSION="2.0"
v2_server() { local repo_root="$1" local port="${2:-9418}"
echo "Git Protocol V2 Server v$GIT_V2_SERVER_VERSION" echo "Repository root: $repo_root" echo "Listening on port: $port"
# Main server loop while true; do # Accept connection (simplified - use proper socket handling in production) read -r line
# Parse initial request if [[ "$line" == "git-upload-pack "* ]]; then service="upload-pack" repo="${line#git-upload-pack }" elif [[ "$line" == "git-receive-pack "* ]]; then service="receive-pack" repo="${line#git-receive-pack }" else send_error "ERR Invalid service request" continue fi
# Validate repository repo_path="$repo_root$repo" if [ ! -d "$repo_path" ]; then send_error "ERR Repository not found" continue fi
# Handle V2 protocol handle_v2_protocol "$service" "$repo_path"
done}
handle_v2_protocol() { local service="$1" local repo_path="$2"
# Read command request read -r command_line
if [[ "$command_line" != "command="* ]]; then # Fallback to V1 protocol handle_v1_fallback "$service" "$repo_path" return fi
command="${command_line#command=}"
# Send capability advertisement send_capabilities "$command"
# Handle command case "$command" in "ls-refs") handle_ls_refs "$repo_path" ;; "fetch") handle_fetch "$repo_path" ;; "push") handle_push "$repo_path" ;; *) send_error "ERR Unknown command: $command" ;; esac}
send_capabilities() { local command="$1"
echo "version 2" echo "capability-advertisement"
# Advertise supported capabilities based on command case "$command" in "ls-refs") echo "ls-refs" echo "symrefs" echo "ref-in-want" ;; "fetch") echo "fetch" echo "filter" echo "side-band" echo "thin-pack" ;; "push") echo "push" echo "report-status" echo "atomic" ;; esac
echo "server-option" echo "object-format=sha1" echo "session-id=$(uuidgen)" echo ""}
handle_ls_refs() { local repo_path="$1"
# Parse client parameters while read -r line; do case "$line" in "symrefs") include_symrefs=true ;; "ref-prefix "*) prefixes+=("${line#ref-prefix }") ;; "") break ;; esac done
# Send reference list git -C "$repo_path" for-each-ref --format="%(refname) %(objectname)" "${prefixes[@]}"
# Send symrefs if requested if [ "$include_symrefs" = true ]; then head_ref=$(git -C "$repo_path" symbolic-ref HEAD 2>/dev/null) if [ -n "$head_ref" ]; then echo "symref HEAD $head_ref" fi fi
echo "" # End of response}
handle_fetch() { local repo_path="$1"
# Parse fetch parameters declare -a wants haves local filter=""
while read -r line; do case "$line" in "want "*) wants+=("${line#want }") ;; "have "*) haves+=("${line#have }") ;; "filter "*) filter="${line#filter }" ;; "done") break ;; esac done
# Perform fetch negotiation # Send acknowledgments for have in "${haves[@]}"; do if git -C "$repo_path" cat-file -e "$have" 2>/dev/null; then echo "ACK $have common" fi done
# Send pack data { echo "packfile" # Generate and send pack file git -C "$repo_path" pack-objects --stdout --thin --delta-base-offset "${wants[@]}" }}
handle_push() { local repo_path="$1"
# Parse push parameters declare -a updates
while read -r line; do case "$line" in "oldref "*) # Parse oldref updates ;; "newref "*) # Parse newref updates ;; "") break ;; esac done
# Perform push operation # Update references # Send status report
echo "ok refs/heads/main" echo ""}
handle_v1_fallback() { local service="$1" local repo_path="$2"
# Fallback to V1 protocol handling case "$service" in "upload-pack") git -C "$repo_path" upload-pack ;; "receive-pack") git -C "$repo_path" receive-pack ;; esac}
send_error() { echo "$1" echo ""}
# Usagev2_server "/var/git" 9418What’s the difference between Git protocol V1 and V2?
Section titled “What’s the difference between Git protocol V1 and V2?”V1 uses stateful connections with mixed command/data streams; V2 uses stateless connections with clear command structure, better performance, and cleaner architecture.
How do I enable Git protocol V2?
Section titled “How do I enable Git protocol V2?”Set git config protocol.version 2 globally or per-remote. Most modern Git clients and servers support V2.
What are the main advantages of V2 over V1?
Section titled “What are the main advantages of V2 over V1?”Stateless design, better performance for large repos, cleaner command structure, enhanced filtering capabilities, and improved extensibility.
Can V2 work with older Git servers?
Section titled “Can V2 work with older Git servers?”V2 clients can fall back to V1 when servers don’t support V2. Use GIT_PROTOCOL=version=1 to force V1 if needed.
What is the ls-refs command in V2?
Section titled “What is the ls-refs command in V2?”Replaces reference advertisement in V1 with a dedicated command for listing and filtering references, enabling more efficient and flexible ref discovery.
How does V2 improve fetch performance?
Section titled “How does V2 improve fetch performance?”Stateless design reduces server load, filtering allows partial clones, and better negotiation algorithms optimize data transfer.
What is object filtering in V2?
Section titled “What is object filtering in V2?”Allows clients to request only specific objects (e.g., blobs under a size limit), enabling partial clones and reducing bandwidth for large repositories.
How do bundle URIs work in V2?
Section titled “How do bundle URIs work in V2?”Servers can advertise pre-computed bundle locations (CDNs, caches) for faster initial clones, offloading server processing.
What is the session-id capability?
Section titled “What is the session-id capability?”Provides unique session identification for tracking and debugging protocol interactions across multiple requests.
Can V2 be used over HTTP?
Section titled “Can V2 be used over HTTP?”Yes, V2 works over HTTP/HTTPS with the same benefits. HTTP servers need to support V2 endpoints and capabilities.
How do I debug V2 protocol issues?
Section titled “How do I debug V2 protocol issues?”Use GIT_TRACE=1 and GIT_TRACE_PACKET=1, check server capability advertisements, and test with GIT_PROTOCOL=version=1 for comparison.
What happens if a V2 client connects to a V1 server?
Section titled “What happens if a V2 client connects to a V1 server?”Client detects lack of V2 support and falls back to V1 protocol automatically.
Are there any V2 features that require special server configuration?
Section titled “Are there any V2 features that require special server configuration?”Yes, filtering requires uploadpack.allowFilter=true, ref-in-want requires uploadpack.allowRefInWant=true, etc.
How does V2 handle authentication?
Section titled “How does V2 handle authentication?”Same as V1 - authentication is transport-specific (SSH keys, HTTP tokens, etc.), not protocol-specific.
What’s the performance impact of enabling V2?
Section titled “What’s the performance impact of enabling V2?”Generally better performance, especially for large repositories and complex operations. Some overhead for small, simple operations.
Can V2 be disabled on servers?
Section titled “Can V2 be disabled on servers?”Yes, servers can be configured to only support V1, though this is not recommended for modern deployments.
How do I monitor V2 usage on a server?
Section titled “How do I monitor V2 usage on a server?”Check Git server logs for V2 command usage, monitor session-ids, and track capability advertisements.
What’s the future of Git protocol development?
Section titled “What’s the future of Git protocol development?”V2 is the current standard with ongoing improvements. Future versions may add more advanced filtering, better compression, and enhanced security features.
Applications of Git protocol V2
Section titled “Applications of Git protocol V2”- High-Performance Git Operations: Enable faster clones, fetches, and pushes for large repositories
- Partial Repository Cloning: Support filtered clones for monorepos and large codebases
- CDN-Accelerated Downloads: Use bundle URIs for faster initial repository access
- Enterprise Security: Implement advanced access controls and audit capabilities
- CI/CD Optimization: Improve build performance with shallow and filtered clones
- Scalable Git Hosting: Support millions of repositories with efficient protocol design