dockerimg: add only git objects to docker image
Instead of copying the entire working directory
(including uncommitted changes, hooks, and config files),
create a bare git repository and use git clone --reference.
This approach:
- Avoids copying uncommitted changes, hooks, and local config files
- Works correctly with git worktrees and submodules
- Reduces Docker image size substantially
- Maintains all git history and functionality
Fixes boldsoftware/sketch#190
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s6af36147e2c4df00k
diff --git a/loop/agent.go b/loop/agent.go
index 841a5ca..ed5c907 100644
--- a/loop/agent.go
+++ b/loop/agent.go
@@ -434,8 +434,6 @@
outsideHostname string
outsideOS string
outsideWorkingDir string
- // URL of the git remote 'origin' if it exists
- gitOrigin string
// MCP manager for handling MCP server connections
mcpManager *mcp.MCPManager
// Port monitor for tracking TCP ports
@@ -742,7 +740,7 @@
// GitOrigin returns the URL of the git remote 'origin' if it exists.
func (a *Agent) GitOrigin() string {
- return a.gitOrigin
+ return a.config.OriginalGitOrigin
}
// GitUsername returns the git user name from the agent config.
@@ -1046,6 +1044,8 @@
OutsideHTTP string
// Outtie's Git server
GitRemoteAddr string
+ // Original git origin URL from host repository, if any
+ OriginalGitOrigin string
// Upstream branch for git work
Upstream string
// Commit to checkout from Outtie
@@ -1116,9 +1116,24 @@
ctx := a.config.Context
slog.InfoContext(ctx, "agent initializing")
+ // If a remote + commit was specified, clone it.
+ if a.config.Commit != "" && a.gitState.gitRemoteAddr != "" {
+ slog.InfoContext(ctx, "cloning git repo", "commit", a.config.Commit)
+ // TODO: --reference-if-able instead?
+ cmd := exec.CommandContext(ctx, "git", "clone", "--reference", "/git-ref", a.gitState.gitRemoteAddr, "/app")
+ if out, err := cmd.CombinedOutput(); err != nil {
+ return fmt.Errorf("failed to clone repository from %s: %s: %w", a.gitState.gitRemoteAddr, out, err)
+ }
+ }
+
+ if a.workingDir != "" {
+ err := os.Chdir(a.workingDir)
+ if err != nil {
+ return fmt.Errorf("failed to change working directory to %s: %w", a.workingDir, err)
+ }
+ }
+
if !ini.NoGit {
- // Capture the original origin before we potentially replace it below
- a.gitOrigin = getGitOrigin(ctx, a.workingDir)
// Configure git user settings
if a.config.GitEmail != "" {
@@ -1143,37 +1158,11 @@
}
}
- // If a remote git addr was specified, we configure the origin remote
- if a.gitState.gitRemoteAddr != "" {
- slog.InfoContext(ctx, "Configuring git remote", slog.String("remote", a.gitState.gitRemoteAddr))
-
- // Remove existing origin remote if it exists
- cmd := exec.CommandContext(ctx, "git", "remote", "remove", "origin")
- cmd.Dir = a.workingDir
- if out, err := cmd.CombinedOutput(); err != nil {
- // Ignore error if origin doesn't exist
- slog.DebugContext(ctx, "git remote remove origin (ignoring if not exists)", slog.String("output", string(out)))
- }
-
- // Add the new remote as origin
- cmd = exec.CommandContext(ctx, "git", "remote", "add", "origin", a.gitState.gitRemoteAddr)
- cmd.Dir = a.workingDir
- if out, err := cmd.CombinedOutput(); err != nil {
- return fmt.Errorf("git remote add origin: %s: %v", out, err)
- }
-
- }
-
// If a commit was specified, we fetch and reset to it.
if a.config.Commit != "" && a.gitState.gitRemoteAddr != "" {
- slog.InfoContext(ctx, "updating git repo", slog.String("commit", a.config.Commit))
+ slog.InfoContext(ctx, "updating git repo", "commit", a.config.Commit)
- cmd := exec.CommandContext(ctx, "git", "stash")
- cmd.Dir = a.workingDir
- if out, err := cmd.CombinedOutput(); err != nil {
- return fmt.Errorf("git stash: %s: %v", out, err)
- }
- cmd = exec.CommandContext(ctx, "git", "fetch", "--prune", "origin")
+ cmd := exec.CommandContext(ctx, "git", "fetch", "--prune", "origin")
cmd.Dir = a.workingDir
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("git fetch: %s: %w", out, err)
@@ -2308,19 +2297,6 @@
return totalAdded, totalRemoved, nil
}
-// getGitOrigin returns the URL of the git remote 'origin' if it exists
-func getGitOrigin(ctx context.Context, dir string) string {
- cmd := exec.CommandContext(ctx, "git", "config", "--get", "remote.origin.url")
- cmd.Dir = dir
- stderr := new(strings.Builder)
- cmd.Stderr = stderr
- out, err := cmd.Output()
- if err != nil {
- return ""
- }
- return strings.TrimSpace(string(out))
-}
-
// systemPromptData contains the data used to render the system prompt template
type systemPromptData struct {
ClientGOOS string