From 9570df7b5426b50c4256d0804cc8a30b14d77039 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 11 Mar 2026 18:34:32 +0200 Subject: fix(sync): stop relying on process cwd --- internal/showcase/showcase.go | 102 ++++++++++------------------------- internal/showcase/showcase_test.go | 27 ++++++++++ internal/sync/branch_analyzer.go | 3 +- internal/sync/branch_sync.go | 8 +-- internal/sync/git_operations.go | 74 +++++++++++++------------ internal/sync/git_operations_test.go | 19 +++++++ internal/sync/repository_setup.go | 14 ----- internal/sync/sync.go | 40 +++++++------- 8 files changed, 139 insertions(+), 148 deletions(-) create mode 100644 internal/sync/git_operations_test.go diff --git a/internal/showcase/showcase.go b/internal/showcase/showcase.go index 5ec43d3..7fef655 100644 --- a/internal/showcase/showcase.go +++ b/internal/showcase/showcase.go @@ -194,6 +194,24 @@ func runCommandWithTimeout(name string, args ...string) (string, error) { return string(out), nil } +func findReadmeContent(repoPath string) ([]byte, string, bool) { + readmeFiles := []string{ + "README.md", "readme.md", "Readme.md", + "README.MD", "README.txt", "readme.txt", + "README", "readme", + } + + for _, readmeFile := range readmeFiles { + path := filepath.Join(repoPath, readmeFile) + content, err := os.ReadFile(path) + if err == nil { + return content, readmeFile, true + } + } + + return nil, "", false +} + // getRepositories returns a list of repository directories in the work directory func (g *Generator) getRepositories() ([]string, error) { entries, err := os.ReadDir(g.workDir) @@ -281,16 +299,7 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool } } - // Change to repository directory - originalDir, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("failed to get current directory: %w", err) - } - defer os.Chdir(originalDir) - - if err := os.Chdir(repoPath); err != nil { - return nil, fmt.Errorf("failed to change to repository directory: %w", err) - } + readmeContent, readmeFile, readmeFound := findReadmeContent(repoPath) // Always extract metadata (not cached) fmt.Printf("Extracting repository metadata...\n") @@ -314,25 +323,9 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool case "amp": // Use README content as stdin and pass the prompt as --execute argument fmt.Printf("Running amp command (stdin payload)\n") - // Find README file - readmeFiles := []string{ - "README.md", "readme.md", "Readme.md", - "README.MD", "README.txt", "readme.txt", - "README", "readme", - } - var readmeContent []byte - var readmeFound bool - for _, readmeFile := range readmeFiles { - content, err := os.ReadFile(readmeFile) - if err == nil { - readmeContent = content - readmeFound = true - fmt.Printf(" Using %s as input\n", readmeFile) - break - } - } if readmeFound { fmt.Printf(" echo | amp --execute \"%s\"\n", prompt) + fmt.Printf(" Using %s as input\n", readmeFile) cmd = exec.Command("amp", "--execute", prompt) cmd.Stdin = strings.NewReader(string(readmeContent)) } else { @@ -346,25 +339,9 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool case "hexai": // Use README content as stdin and pass the prompt as argument fmt.Printf("Running hexai command (stdin payload)\n") - // Find README file - readmeFiles := []string{ - "README.md", "readme.md", "Readme.md", - "README.MD", "README.txt", "readme.txt", - "README", "readme", - } - var readmeContent []byte - var readmeFound bool - for _, readmeFile := range readmeFiles { - content, err := os.ReadFile(readmeFile) - if err == nil { - readmeContent = content - readmeFound = true - fmt.Printf(" Using %s as input\n", readmeFile) - break - } - } if readmeFound { fmt.Printf(" echo | hexai \"%s\"\n", prompt) + fmt.Printf(" Using %s as input\n", readmeFile) cmd = exec.Command("hexai", prompt) cmd.Stdin = strings.NewReader(string(readmeContent)) } else { @@ -375,27 +352,9 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool // For aichat, we need to read README.md and pipe it to aichat fmt.Printf("Running aichat command:\n") - // Find README file - readmeFiles := []string{ - "README.md", "readme.md", "Readme.md", - "README.MD", "README.txt", "readme.txt", - "README", "readme", - } - - var readmeContent []byte - var readmeFound bool - for _, readmeFile := range readmeFiles { - content, err := os.ReadFile(readmeFile) - if err == nil { - readmeContent = content - readmeFound = true - fmt.Printf(" Using %s as input\n", readmeFile) - break - } - } - if readmeFound { fmt.Printf(" echo | aichat \"%s\"\n", prompt) + fmt.Printf(" Using %s as input\n", readmeFile) cmd = exec.Command("aichat", prompt) cmd.Stdin = strings.NewReader(string(readmeContent)) } else { @@ -408,6 +367,7 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool } if cmd != nil { + cmd.Dir = repoPath if output, err := cmd.Output(); err == nil { summary = strings.TrimSpace(string(output)) } @@ -415,18 +375,10 @@ func (g *Generator) generateProjectSummary(repoName string, forceRegenerate bool // Fallback: create a minimal summary from README if AI unavailable/failed if summary == "" { - readmeFiles := []string{ - "README.md", "readme.md", "Readme.md", - "README.MD", "README.txt", "readme.txt", - "README", "readme", - } - for _, readmeFile := range readmeFiles { - if content, err := os.ReadFile(readmeFile); err == nil { - parts := strings.Split(strings.TrimSpace(string(content)), "\n\n") - if len(parts) > 0 { - summary = strings.TrimSpace(parts[0]) - break - } + if readmeFound { + parts := strings.Split(strings.TrimSpace(string(readmeContent)), "\n\n") + if len(parts) > 0 { + summary = strings.TrimSpace(parts[0]) } } if summary == "" { diff --git a/internal/showcase/showcase_test.go b/internal/showcase/showcase_test.go index 3fce064..f480bdb 100644 --- a/internal/showcase/showcase_test.go +++ b/internal/showcase/showcase_test.go @@ -1,6 +1,8 @@ package showcase import ( + "os" + "path/filepath" "reflect" "strings" "testing" @@ -122,3 +124,28 @@ func TestFormatGemtext_IncludesRankHistoryInHeader(t *testing.T) { t.Fatalf("rank history was not rendered in header: %s", content) } } + +func TestFindReadmeContent_UsesRepoPathWithoutChangingCWD(t *testing.T) { + t.Parallel() + + repoPath := filepath.Join(t.TempDir(), "repo") + if err := os.MkdirAll(repoPath, 0755); err != nil { + t.Fatalf("failed to create repo dir: %v", err) + } + + readmePath := filepath.Join(repoPath, "README.md") + if err := os.WriteFile(readmePath, []byte("repo summary"), 0644); err != nil { + t.Fatalf("failed to write readme: %v", err) + } + + content, readmeFile, found := findReadmeContent(repoPath) + if !found { + t.Fatal("expected README to be found") + } + if readmeFile != "README.md" { + t.Fatalf("expected README.md, got %q", readmeFile) + } + if string(content) != "repo summary" { + t.Fatalf("unexpected README content: %q", string(content)) + } +} diff --git a/internal/sync/branch_analyzer.go b/internal/sync/branch_analyzer.go index 7499996..04a60d7 100644 --- a/internal/sync/branch_analyzer.go +++ b/internal/sync/branch_analyzer.go @@ -3,7 +3,6 @@ package sync import ( "fmt" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -183,7 +182,7 @@ func (s *Syncer) getLastCommitTime(remoteName, branch string) (time.Time, error) } // Get Unix timestamp of last commit - cmd := exec.Command("git", "log", "-1", "--format=%ct", ref) + cmd := gitCommand(s.repoPath(), "log", "-1", "--format=%ct", ref) output, err := cmd.Output() if err != nil { return time.Time{}, err diff --git a/internal/sync/branch_sync.go b/internal/sync/branch_sync.go index eafb551..a667ee2 100644 --- a/internal/sync/branch_sync.go +++ b/internal/sync/branch_sync.go @@ -24,7 +24,7 @@ func (s *Syncer) trackRemotesWithBranch(branch string, remotes map[string]*confi } // mergeFromRemotes merges changes from all remotes that have the branch -func mergeFromRemotes(branch string, remotesWithBranch map[string]bool) error { +func mergeFromRemotes(repoPath, branch string, remotesWithBranch map[string]bool) error { if len(remotesWithBranch) == 0 { fmt.Printf(" Branch %s is local only, will push to all remotes\n", branch) return nil @@ -32,7 +32,7 @@ func mergeFromRemotes(branch string, remotesWithBranch map[string]bool) error { // Merge changes from all remotes that have this branch for remoteName := range remotesWithBranch { - if err := mergeBranch(remoteName, branch); err != nil { + if err := mergeBranch(repoPath, remoteName, branch); err != nil { return err } } @@ -41,7 +41,7 @@ func mergeFromRemotes(branch string, remotesWithBranch map[string]bool) error { } // pushToAllRemotes pushes the branch to all configured remotes -func pushToAllRemotes(branch string, remotes map[string]*config.Organization, remotesWithBranch map[string]bool) error { +func pushToAllRemotes(repoPath, branch string, remotes map[string]*config.Organization, remotesWithBranch map[string]bool) error { for remoteName, org := range remotes { // Check if this remote has the branch remoteHasBranch := remotesWithBranch[remoteName] @@ -52,7 +52,7 @@ func pushToAllRemotes(branch string, remotes map[string]*config.Organization, re fmt.Printf(" Pushing to %s (%s)...\n", remoteName, org.Host) } - if err := pushBranchWithBackupSupport(remoteName, branch, remoteHasBranch, org); err != nil { + if err := pushBranchWithBackupSupport(repoPath, remoteName, branch, remoteHasBranch, org); err != nil { return err } } diff --git a/internal/sync/git_operations.go b/internal/sync/git_operations.go index 0bd698e..62a530b 100644 --- a/internal/sync/git_operations.go +++ b/internal/sync/git_operations.go @@ -11,9 +11,17 @@ import ( "codeberg.org/snonux/gitsyncer/internal/config" ) +func gitCommand(repoPath string, args ...string) *exec.Cmd { + cmd := exec.Command("git", args...) + if repoPath != "" { + cmd.Dir = repoPath + } + return cmd +} + // checkForMergeConflicts checks if the repository has merge conflicts -func checkForMergeConflicts() (bool, string, error) { - cmd := exec.Command("git", "status", "--porcelain") +func checkForMergeConflicts(repoPath string) (bool, string, error) { + cmd := gitCommand(repoPath, "status", "--porcelain") output, err := cmd.Output() if err != nil { return false, "", err @@ -28,21 +36,21 @@ func checkForMergeConflicts() (bool, string, error) { } // stashChanges stashes uncommitted changes -func stashChanges() error { +func stashChanges(repoPath string) error { fmt.Println(" Stashing uncommitted changes...") - return exec.Command("git", "stash", "push", "-m", "gitsyncer-auto-stash").Run() + return gitCommand(repoPath, "stash", "push", "-m", "gitsyncer-auto-stash").Run() } // popStash attempts to pop the stash (used in defer) -func popStash() { - exec.Command("git", "stash", "pop").Run() +func popStash(repoPath string) { + gitCommand(repoPath, "stash", "pop").Run() } // mergeBranch merges a branch from a remote -func mergeBranch(remoteName, branch string) error { +func mergeBranch(repoPath, remoteName, branch string) error { fmt.Printf(" Merging from %s/%s...\n", remoteName, branch) - cmd := exec.Command("git", "merge", fmt.Sprintf("%s/%s", remoteName, branch), "--no-edit") + cmd := gitCommand(repoPath, "merge", fmt.Sprintf("%s/%s", remoteName, branch), "--no-edit") output, err := cmd.CombinedOutput() if err != nil { @@ -57,8 +65,8 @@ func mergeBranch(remoteName, branch string) error { } // pushBranch pushes a branch to a remote -func pushBranch(remoteName, branch string, remoteHasBranch bool) error { - cmd := exec.Command("git", "push", remoteName, branch, "--tags") +func pushBranch(repoPath, remoteName, branch string, remoteHasBranch bool) error { + cmd := gitCommand(repoPath, "push", remoteName, branch, "--tags") output, err := cmd.CombinedOutput() if err != nil { @@ -74,7 +82,7 @@ func pushBranch(remoteName, branch string, remoteHasBranch bool) error { if isBranchMissing(outputStr) { fmt.Printf(" Creating new branch on %s\n", remoteName) // Try again with -u flag to set upstream - cmd = exec.Command("git", "push", "-u", remoteName, branch, "--tags") + cmd = gitCommand(repoPath, "push", "-u", remoteName, branch, "--tags") if err := cmd.Run(); err != nil { return fmt.Errorf("failed to push to %s: %w", remoteName, err) } @@ -103,8 +111,8 @@ func isBranchMissing(output string) bool { } // getRemotesList extracts unique remote names from git remote -v output -func getRemotesList() (map[string]bool, error) { - cmd := exec.Command("git", "remote", "-v") +func getRemotesList(repoPath string) (map[string]bool, error) { + cmd := gitCommand(repoPath, "remote", "-v") output, err := cmd.Output() if err != nil { return nil, fmt.Errorf("failed to list remotes: %w", err) @@ -126,14 +134,14 @@ func getRemotesList() (map[string]bool, error) { } // fetchRemote fetches from a single remote with error handling -func fetchRemote(remote string) error { - cmd := exec.Command("git", "fetch", remote, "--prune", "--tags") +func fetchRemote(repoPath, remote string) error { + cmd := gitCommand(repoPath, "fetch", remote, "--prune", "--tags") output, err := cmd.CombinedOutput() if err != nil { // Check if it's a tag conflict error if bytes.Contains(output, []byte("would clobber existing tag")) { - return handleTagConflict(remote, output) + return handleTagConflict(repoPath, remote, output) } // Check if it's because the repository doesn't exist @@ -147,7 +155,7 @@ func fetchRemote(remote string) error { } // handleTagConflict provides a detailed error message for tag conflicts. -func handleTagConflict(remote string, output []byte) error { +func handleTagConflict(repoPath, remote string, output []byte) error { var conflictDetails strings.Builder conflictDetails.WriteString("tag conflict detected while fetching from remote: ") conflictDetails.WriteString(remote) @@ -159,8 +167,8 @@ func handleTagConflict(remote string, output []byte) error { for _, match := range matches { if len(match) > 1 { tag := string(match[1]) - localHash, _ := getTagCommitHash(tag, "local") - remoteHash, _ := getTagCommitHash(tag, remote) + localHash, _ := getTagCommitHash(repoPath, tag, "local") + remoteHash, _ := getTagCommitHash(repoPath, tag, remote) conflictDetails.WriteString(fmt.Sprintf("\n - Tag: %s\n Local: %s\n Remote: %s", tag, localHash, remoteHash)) } } @@ -169,12 +177,12 @@ func handleTagConflict(remote string, output []byte) error { } // getTagCommitHash retrieves the commit hash for a given tag, either locally or from a remote. -func getTagCommitHash(tag, source string) (string, error) { +func getTagCommitHash(repoPath, tag, source string) (string, error) { var cmd *exec.Cmd if source == "local" { - cmd = exec.Command("git", "rev-parse", tag+"^{\\}") + cmd = gitCommand(repoPath, "rev-parse", tag+"^{\\}") } else { - cmd = exec.Command("git", "ls-remote", "--tags", source, tag) + cmd = gitCommand(repoPath, "ls-remote", "--tags", source, tag) } output, err := cmd.Output() @@ -187,8 +195,8 @@ func getTagCommitHash(tag, source string) (string, error) { } // checkoutExistingBranch tries to checkout an existing branch -func checkoutExistingBranch(branch string) error { - cmd := exec.Command("git", "checkout", branch) +func checkoutExistingBranch(repoPath, branch string) error { + cmd := gitCommand(repoPath, "checkout", branch) output, err := cmd.CombinedOutput() if err != nil { fmt.Printf(" Initial checkout failed: %s\n", strings.TrimSpace(string(output))) @@ -198,8 +206,8 @@ func checkoutExistingBranch(branch string) error { } // createTrackingBranch creates a new branch tracking a remote branch -func createTrackingBranch(branch, remoteName string) error { - cmd := exec.Command("git", "checkout", "-b", branch, fmt.Sprintf("%s/%s", remoteName, branch)) +func createTrackingBranch(repoPath, branch, remoteName string) error { + cmd := gitCommand(repoPath, "checkout", "-b", branch, fmt.Sprintf("%s/%s", remoteName, branch)) output, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("failed to create tracking branch: %s", string(output)) @@ -265,8 +273,8 @@ func createSSHBareRepository(sshHost, repoPath string) error { } // pushBranchWithBackupSupport pushes a branch to a remote, creating SSH repos if needed -func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool, org *config.Organization) error { - cmd := exec.Command("git", "push", remoteName, branch, "--tags") +func pushBranchWithBackupSupport(repoPath, remoteName, branch string, remoteHasBranch bool, org *config.Organization) error { + cmd := gitCommand(repoPath, "push", remoteName, branch, "--tags") output, err := cmd.CombinedOutput() if err != nil { @@ -276,7 +284,7 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool // If it's an SSH backup location, try to create the repository if org.BackupLocation && org.IsSSH() { // Get the repository name from the remote URL - remoteURL, err := getRemoteURL(remoteName) + remoteURL, err := getRemoteURL(repoPath, remoteName) if err != nil { return fmt.Errorf("failed to get remote URL: %w", err) } @@ -293,7 +301,7 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool } // Try pushing again - cmd = exec.Command("git", "push", remoteName, branch, "--tags") + cmd = gitCommand(repoPath, "push", remoteName, branch, "--tags") if err := cmd.Run(); err != nil { return fmt.Errorf("failed to push after creating repository: %w", err) } @@ -310,7 +318,7 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool if isBranchMissing(outputStr) { fmt.Printf(" Creating new branch on %s\n", remoteName) // Try again with -u flag to set upstream - cmd = exec.Command("git", "push", "-u", remoteName, branch, "--tags") + cmd = gitCommand(repoPath, "push", "-u", remoteName, branch, "--tags") if err := cmd.Run(); err != nil { return fmt.Errorf("failed to push to %s: %w", remoteName, err) } @@ -328,8 +336,8 @@ func pushBranchWithBackupSupport(remoteName, branch string, remoteHasBranch bool } // getRemoteURL gets the URL for a given remote -func getRemoteURL(remoteName string) (string, error) { - cmd := exec.Command("git", "remote", "get-url", remoteName) +func getRemoteURL(repoPath, remoteName string) (string, error) { + cmd := gitCommand(repoPath, "remote", "get-url", remoteName) output, err := cmd.Output() if err != nil { return "", err diff --git a/internal/sync/git_operations_test.go b/internal/sync/git_operations_test.go new file mode 100644 index 0000000..03ddb81 --- /dev/null +++ b/internal/sync/git_operations_test.go @@ -0,0 +1,19 @@ +package sync + +import "testing" + +func TestGitCommand_SetsDir(t *testing.T) { + cmd := gitCommand("/tmp/example-repo", "status") + + if cmd.Dir != "/tmp/example-repo" { + t.Fatalf("expected command dir to be set, got %q", cmd.Dir) + } +} + +func TestGitCommand_LeavesDirEmptyForGlobalCommands(t *testing.T) { + cmd := gitCommand("", "ls-remote", "--tags", "origin", "v1.0.0") + + if cmd.Dir != "" { + t.Fatalf("expected empty dir for global command, got %q", cmd.Dir) + } +} diff --git a/internal/sync/repository_setup.go b/internal/sync/repository_setup.go index 7e2c40e..e255274 100644 --- a/internal/sync/repository_setup.go +++ b/internal/sync/repository_setup.go @@ -96,20 +96,6 @@ func (s *Syncer) setupExistingRepository(repoPath string) error { return nil } -// changeToRepoDirectory changes to the repository directory and returns a function to restore the original directory -func changeToRepoDirectory(repoPath string) (func(), error) { - originalDir, err := os.Getwd() - if err != nil { - return nil, fmt.Errorf("failed to get current directory: %w", err) - } - - if err := os.Chdir(repoPath); err != nil { - return nil, fmt.Errorf("failed to change to repository directory: %w", err) - } - - return func() { os.Chdir(originalDir) }, nil -} - // getRemotesMap creates a map of remote names to organizations func (s *Syncer) getRemotesMap() map[string]*config.Organization { remotes := make(map[string]*config.Organization) diff --git a/internal/sync/sync.go b/internal/sync/sync.go index 0f2f479..ba03e0f 100644 --- a/internal/sync/sync.go +++ b/internal/sync/sync.go @@ -60,13 +60,6 @@ func (s *Syncer) SyncRepository(repoName string) error { return err } - // Change to repository directory - restoreDir, err := changeToRepoDirectory(repoPath) - if err != nil { - return err - } - defer restoreDir() - // Fetch all remotes fmt.Printf("Fetching updates from all remotes...\n") if err := s.fetchAll(); err != nil { @@ -114,6 +107,10 @@ func (s *Syncer) SyncRepository(repoName string) error { return nil } +func (s *Syncer) repoPath() string { + return filepath.Join(s.workDir, s.repoName) +} + // EnsureRepositoryCloned ensures a repository is cloned locally without syncing // This is used for showcase-only mode func (s *Syncer) EnsureRepositoryCloned(repoName string) error { @@ -219,7 +216,7 @@ func (s *Syncer) addRemote(repoPath string, org *config.Organization) error { // Note: We use individual fetches instead of --all to handle missing repositories gracefully func (s *Syncer) fetchAll() error { // Get list of remotes - remotes, err := getRemotesList() + remotes, err := getRemotesList(s.repoPath()) if err != nil { return err } @@ -247,7 +244,7 @@ func (s *Syncer) fetchAll() error { } fmt.Printf("Fetching %s\n", remote) - if err := fetchRemote(remote); err != nil { + if err := fetchRemote(s.repoPath(), remote); err != nil { return err } } @@ -257,7 +254,7 @@ func (s *Syncer) fetchAll() error { // getAllBranches gets all unique branches from all remotes func (s *Syncer) getAllBranches() ([]string, error) { - cmd := exec.Command("git", "branch", "-r") + cmd := gitCommand(s.repoPath(), "branch", "-r") output, err := cmd.Output() if err != nil { return nil, err @@ -274,13 +271,15 @@ func (s *Syncer) getAllBranches() ([]string, error) { // syncBranch synchronizes a specific branch across all remotes func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organization) error { + repoPath := s.repoPath() + // Handle merge conflicts and uncommitted changes stashed, err := s.handleWorkingDirectoryState() if err != nil { return err } if stashed { - defer popStash() + defer popStash(repoPath) } // Create or checkout the branch @@ -292,33 +291,34 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati remotesWithBranch := s.trackRemotesWithBranch(branch, remotes) // Merge changes from remotes - if err := mergeFromRemotes(branch, remotesWithBranch); err != nil { + if err := mergeFromRemotes(repoPath, branch, remotesWithBranch); err != nil { return err } // Push to all remotes - return pushToAllRemotes(branch, remotes, remotesWithBranch) + return pushToAllRemotes(repoPath, branch, remotes, remotesWithBranch) } // handleWorkingDirectoryState checks for conflicts and stashes changes if needed // Returns true if changes were stashed func (s *Syncer) handleWorkingDirectoryState() (bool, error) { - hasConflicts, statusStr, err := checkForMergeConflicts() + repoPath := s.repoPath() + hasConflicts, statusStr, err := checkForMergeConflicts(repoPath) if err != nil || statusStr == "" { return false, nil } if hasConflicts { // Get absolute path for clarity - absPath, err := filepath.Abs(s.workDir) + absPath, err := filepath.Abs(repoPath) if err != nil { - absPath = s.workDir + absPath = repoPath } return false, fmt.Errorf("repository has unresolved merge conflicts\nPlease resolve conflicts in: %s\nOr delete the directory to start fresh: rm -rf %s", absPath, absPath) } // If we have uncommitted changes but no conflicts, try to stash them - if err := stashChanges(); err != nil { + if err := stashChanges(repoPath); err != nil { return false, fmt.Errorf("failed to stash changes: %w", err) } return true, nil @@ -327,7 +327,7 @@ func (s *Syncer) handleWorkingDirectoryState() (bool, error) { // checkoutBranch checks out a branch, creating it if necessary func (s *Syncer) checkoutBranch(branch string) error { // First try to checkout existing branch - if err := checkoutExistingBranch(branch); err == nil { + if err := checkoutExistingBranch(s.repoPath(), branch); err == nil { return nil } @@ -337,7 +337,7 @@ func (s *Syncer) checkoutBranch(branch string) error { remoteName := s.getRemoteName(org) if s.remoteBranchExists(remoteName, branch) { - return createTrackingBranch(branch, remoteName) + return createTrackingBranch(s.repoPath(), branch, remoteName) } } @@ -346,7 +346,7 @@ func (s *Syncer) checkoutBranch(branch string) error { // remoteBranchExists checks if a branch exists on a remote func (s *Syncer) remoteBranchExists(remoteName, branch string) bool { - cmd := exec.Command("git", "branch", "-r", "--list", fmt.Sprintf("%s/%s", remoteName, branch)) + cmd := gitCommand(s.repoPath(), "branch", "-r", "--list", fmt.Sprintf("%s/%s", remoteName, branch)) output, err := cmd.Output() if err != nil { return false -- cgit v1.2.3