cmd/sketch: add -upstream flag for git branch management

To be used in future work.

Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s40fdfb9a579bf6f2k
diff --git a/cmd/sketch/main.go b/cmd/sketch/main.go
index ce5646e..6e3cfbe 100644
--- a/cmd/sketch/main.go
+++ b/cmd/sketch/main.go
@@ -202,6 +202,7 @@
 	mounts            StringSliceFlag
 	termUI            bool
 	gitRemoteURL      string
+	upstream          string
 	commit            string
 	outsideHTTP       string
 	branchPrefix      string
@@ -250,6 +251,7 @@
 	internalFlags.StringVar(&flags.outsideWorkingDir, "outside-working-dir", "", "(internal) working dir on the outside system")
 	internalFlags.StringVar(&flags.sketchBinaryLinux, "sketch-binary-linux", "", "(development) path to a pre-built sketch binary for linux")
 	internalFlags.StringVar(&flags.gitRemoteURL, "git-remote-url", "", "(internal) git remote for outside sketch")
+	internalFlags.StringVar(&flags.upstream, "upstream", "", "(internal) upstream branch for git work")
 	internalFlags.StringVar(&flags.commit, "commit", "", "(internal) the git commit reference to check out from git remote url")
 	internalFlags.StringVar(&flags.outsideHTTP, "outside-http", "", "(internal) host for outside sketch")
 
@@ -509,6 +511,7 @@
 		InDocker:      flags.outsideHostname != "",
 		OneShot:       flags.oneShot,
 		GitRemoteAddr: flags.gitRemoteURL,
+		Upstream:      flags.upstream,
 		OutsideHTTP:   flags.outsideHTTP,
 		Commit:        flags.commit,
 		BranchPrefix:  flags.branchPrefix,
diff --git a/dockerimg/dockerimg.go b/dockerimg/dockerimg.go
index da3ccbb..42d9e14 100644
--- a/dockerimg/dockerimg.go
+++ b/dockerimg/dockerimg.go
@@ -110,6 +110,9 @@
 
 	GitRemoteUrl string
 
+	// Upstream branch for git work
+	Upstream string
+
 	// Commit hash to checkout from GetRemoteUrl
 	Commit string
 
@@ -201,6 +204,13 @@
 	} else {
 		commit = strings.TrimSpace(string(out))
 	}
+
+	var upstream string
+	if out, err := combinedOutput(ctx, "git", "branch", "--show-current"); err != nil {
+		slog.DebugContext(ctx, "git branch --show-current failed (continuing)", "error", err)
+	} else {
+		upstream = strings.TrimSpace(string(out))
+	}
 	if out, err := combinedOutput(ctx, "git", "config", "http.receivepack", "true"); err != nil {
 		return fmt.Errorf("git config http.receivepack true: %s: %w", out, err)
 	}
@@ -212,6 +222,7 @@
 
 	config.OutsideHTTP = fmt.Sprintf("http://sketch:%s@host.docker.internal:%s", gitSrv.pass, gitSrv.gitPort)
 	config.GitRemoteUrl = fmt.Sprintf("http://sketch:%s@host.docker.internal:%s/.git", gitSrv.pass, gitSrv.gitPort)
+	config.Upstream = upstream
 	config.Commit = commit
 
 	// Create the sketch container
@@ -555,6 +566,7 @@
 			panic("Commit should have been set when GitRemoteUrl was set")
 		}
 		cmdArgs = append(cmdArgs, "-commit="+config.Commit)
+		cmdArgs = append(cmdArgs, "-upstream="+config.Upstream)
 	}
 	if config.OutsideHTTP != "" {
 		cmdArgs = append(cmdArgs, "-outside-http="+config.OutsideHTTP)
diff --git a/loop/agent.go b/loop/agent.go
index fd01f33..466cec0 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -320,6 +320,7 @@
 	mu            sync.Mutex      // protects following
 	lastHEAD      string          // hash of the last HEAD that was pushed to the host
 	gitRemoteAddr string          // HTTP URL of the host git repo
+	upstream      string          // upstream branch for git work
 	seenCommits   map[string]bool // Track git commits we've already seen (by hash)
 	branchName    string
 }
@@ -336,6 +337,12 @@
 	return ags.branchName
 }
 
+func (ags *AgentGitState) Upstream() string {
+	ags.mu.Lock()
+	defer ags.mu.Unlock()
+	return ags.upstream
+}
+
 type Agent struct {
 	convo             ConvoInterface
 	config            AgentConfig // config for this agent
@@ -914,6 +921,11 @@
 	return a.originalBudget
 }
 
+// Upstream returns the upstream branch for git work
+func (a *Agent) Upstream() string {
+	return a.gitState.Upstream()
+}
+
 // AgentConfig contains configuration for creating a new Agent.
 type AgentConfig struct {
 	Context      context.Context
@@ -936,6 +948,8 @@
 	OutsideHTTP string
 	// Outtie's Git server
 	GitRemoteAddr string
+	// Upstream branch for git work
+	Upstream string
 	// Commit to checkout from Outtie
 	Commit string
 	// Prefix for git branches created by sketch
@@ -960,6 +974,7 @@
 		gitState: AgentGitState{
 			seenCommits:   make(map[string]bool),
 			gitRemoteAddr: config.GitRemoteAddr,
+			upstream:      config.Upstream,
 		},
 		outsideHostname:      config.OutsideHostname,
 		outsideOS:            config.OutsideOS,