loop: set upstream tracking for sketch branches on outie

Fixes boldsoftware/sketch#143

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s782ec3188bf0856ak
diff --git a/dockerimg/githttp.go b/dockerimg/githttp.go
index eaeb23a..fae1678 100644
--- a/dockerimg/githttp.go
+++ b/dockerimg/githttp.go
@@ -1,6 +1,7 @@
 package dockerimg
 
 import (
+	"bytes"
 	"context"
 	"crypto/subtle"
 	_ "embed"
@@ -13,12 +14,16 @@
 	"path/filepath"
 	"runtime"
 	"strings"
+	"text/template"
 	"time"
 )
 
 //go:embed pre-receive.sh
 var preReceiveScript string
 
+//go:embed post-receive.sh
+var postReceiveScript string
+
 type gitHTTP struct {
 	gitRepoRoot string
 	hooksDir    string
@@ -41,7 +46,7 @@
 // Note:
 //   - Error propagation from origin push to user push
 //   - Session isolation with temporary hooks directory
-func setupHooksDir(gitRepoRoot string) (string, error) {
+func setupHooksDir(upstream string) (string, error) {
 	hooksDir, err := os.MkdirTemp("", "sketch-git-hooks-*")
 	if err != nil {
 		return "", fmt.Errorf("failed to create hooks directory: %w", err)
@@ -52,6 +57,21 @@
 		return "", fmt.Errorf("failed to write pre-receive hook: %w", err)
 	}
 
+	if upstream != "" {
+		tmpl, err := template.New("post-receive").Parse(postReceiveScript)
+		if err != nil {
+			return "", fmt.Errorf("failed to parse post-receive template: %w", err)
+		}
+		var buf bytes.Buffer
+		if err := tmpl.Execute(&buf, map[string]string{"Upstream": upstream}); err != nil {
+			return "", fmt.Errorf("failed to execute post-receive template: %w", err)
+		}
+		postReceiveHook := filepath.Join(hooksDir, "post-receive")
+		if err := os.WriteFile(postReceiveHook, buf.Bytes(), 0o755); err != nil {
+			return "", fmt.Errorf("failed to write post-receive hook: %w", err)
+		}
+	}
+
 	return hooksDir, nil
 }
 
@@ -151,11 +171,14 @@
 
 	w.Header().Set("Cache-Control", "no-cache")
 
-	args := []string{"http-backend"}
+	var args []string
 	if g.hooksDir != "" {
-		// Use -c flag to set core.hooksPath for this git command only
-		args = []string{"-c", "core.hooksPath=" + g.hooksDir, "-c", "receive.denyCurrentBranch=refuse", "http-backend"}
+		args = append(args,
+			"-c", "core.hooksPath="+g.hooksDir,
+			"-c", "receive.denyCurrentBranch=refuse",
+		)
 	}
+	args = append(args, "http-backend")
 
 	h := &cgi.Handler{
 		Path: gitBin,