all repos

mugit @ dc036ea3bf4fedd8fb3b4530070256fecc2d09be

馃惍 git server that your cow will love
3 files changed, 19 insertions(+), 14 deletions(-)
git: use v2 protocol only when client asks for it
Author: Oleksandr Smirnov olexsmir@gmail.com
Committed at: 2026-03-02 14:58:03 +0200
Authored at: 2026-03-02 14:54:16 +0200
Change ID: qozwkkmwqtxkmszvpqvzyxnvnuooolxs
Parent: 91e70b7
M internal/git/gitx/gitx.go
路路路
        2
        2
         

      
        3
        3
         import (

      
        4
        4
         	"context"

      
        
        5
        +	"fmt"

      
        5
        6
         	"io"

      
        6
        7
         	"os/exec"

      
        7
        8
         	"syscall"

      路路路
        13
        14
         }

      
        14
        15
         

      
        15
        16
         type cmdOpts struct {

      
        16
        
        -	Cmd     []string

      
        17
        
        -	RepoDir string

      
        18
        
        -	Stdin   io.Reader

      
        19
        
        -	Stdout  io.Writer

      
        20
        
        -	Stderr  io.Writer

      
        
        17
        +	Cmd         []string

      
        
        18
        +	GitProtocol string

      
        
        19
        +	RepoDir     string

      
        
        20
        +	Stdin       io.Reader

      
        
        21
        +	Stdout      io.Writer

      
        
        22
        +	Stderr      io.Writer

      
        21
        23
         }

      
        22
        24
         

      
        23
        25
         func gitCmd(ctx context.Context, opts cmdOpts) error {

      
        24
        26
         	opts.Cmd = append(opts.Cmd, ".")

      
        25
        27
         	cmd := exec.CommandContext(ctx, "git", opts.Cmd...)

      
        26
        28
         	cmd.Dir = opts.RepoDir

      
        27
        
        -	cmd.Env = gitEnv

      
        
        29
        +	cmd.Env = append(gitEnv, fmt.Sprintf("GIT_PROTOCOL=%s", opts.GitProtocol))

      
        28
        30
         	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}

      
        29
        31
         	cmd.Stdin = opts.Stdin

      
        30
        32
         	cmd.Stdout = opts.Stdout

      
M internal/git/gitx/pack.go
路路路
        4
        4
         	"context"

      
        5
        5
         	"fmt"

      
        6
        6
         	"io"

      
        
        7
        +	"strings"

      
        7
        8
         )

      
        8
        9
         

      
        9
        10
         // InfoRefs executes git-upload-pack --advertise-refs for smart-HTTP discovery.

      
        10
        
        -func InfoRefs(ctx context.Context, repoDir string, out io.Writer) error {

      
        11
        
        -	if err := PackLine(out, "# service=git-upload-pack\n"); err != nil {

      
        12
        
        -		return fmt.Errorf("write pack line: %w", err)

      
        13
        
        -	}

      
        14
        
        -

      
        15
        
        -	if err := PackFlush(out); err != nil {

      
        16
        
        -		return fmt.Errorf("flush pack: %w", err)

      
        
        11
        +func InfoRefs(ctx context.Context, repoDir, protocol string, out io.Writer) error {

      
        
        12
        +	if !strings.Contains(protocol, "version=2") {

      
        
        13
        +		if err := PackLine(out, "# service=git-upload-pack\n"); err != nil {

      
        
        14
        +			return fmt.Errorf("write pack line: %w", err)

      
        
        15
        +		}

      
        
        16
        +		if err := PackFlush(out); err != nil {

      
        
        17
        +			return fmt.Errorf("flush pack: %w", err)

      
        
        18
        +		}

      
        17
        19
         	}

      
        18
        20
         

      
        19
        21
         	if err := gitCmd(ctx, cmdOpts{

      
M internal/handlers/git.go
路路路
        19
        19
         	}

      
        20
        20
         

      
        21
        21
         	service := r.URL.Query().Get("service")

      
        
        22
        +	gitProtocol := r.Header.Get("Git-Protocol")

      
        22
        23
         	switch service {

      
        23
        24
         	case "git-upload-pack":

      
        24
        25
         		w.Header().Set("Content-Type", "application/x-git-upload-pack-advertisement")

      路路路
        26
        27
         		w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate")

      
        27
        28
         

      
        28
        29
         		w.WriteHeader(http.StatusOK)

      
        29
        
        -		if err := gitx.InfoRefs(r.Context(), path, w); err != nil {

      
        
        30
        +		if err := gitx.InfoRefs(r.Context(), path, gitProtocol, w); err != nil {

      
        30
        31
         			h.gitError(w, http.StatusInternalServerError, err.Error())

      
        31
        32
         			slog.Error("git: info/refs", "err", err)

      
        32
        33
         			return