summaryrefslogtreecommitdiff
path: root/internal/sync/sync.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-06-23 23:38:55 +0300
committerPaul Buetow <paul@buetow.org>2025-06-23 23:38:55 +0300
commit42d3df9fe18663f5c6f7067b964f0b09071910e6 (patch)
treefff4b4708115caa29c4daadc1444e02ab14c41b7 /internal/sync/sync.go
parent006724744a943aad877a92406a5e2b4d5d12acd3 (diff)
Add debugging features and improve error handling
- Add --test-github-token flag to validate GitHub authentication - Improve error messages for 401 authentication failures - Add merge conflict detection before sync attempts - Stop sync on first error for easier debugging - Add GitHub repo creation support for --sync and --sync-all commands - Add detailed token loading debug output - Create test script for GitHub token validation 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'internal/sync/sync.go')
-rw-r--r--internal/sync/sync.go42
1 files changed, 40 insertions, 2 deletions
diff --git a/internal/sync/sync.go b/internal/sync/sync.go
index 7f9b81e..a22089d 100644
--- a/internal/sync/sync.go
+++ b/internal/sync/sync.go
@@ -250,6 +250,35 @@ 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 {
+ // First check if we have unresolved merge conflicts
+ cmd := exec.Command("git", "status", "--porcelain")
+ output, err := cmd.Output()
+ if err == nil && len(output) > 0 {
+ // Check for merge conflicts
+ statusStr := string(output)
+ if strings.Contains(statusStr, "UU ") || strings.Contains(statusStr, "AA ") || strings.Contains(statusStr, "DD ") {
+ // Get the repo name from the work directory
+ repoName := filepath.Base(s.workDir)
+ if repoName == ".gitsyncer-work" || repoName == "" {
+ // If we're in the work directory itself, extract from current directory
+ cmd := exec.Command("git", "rev-parse", "--show-toplevel")
+ if output, err := cmd.Output(); err == nil {
+ repoName = filepath.Base(strings.TrimSpace(string(output)))
+ }
+ }
+ return fmt.Errorf("repository has unresolved merge conflicts - please resolve manually or delete %s", s.workDir)
+ }
+ // If we have uncommitted changes but no conflicts, try to stash them
+ fmt.Println(" Stashing uncommitted changes...")
+ if err := exec.Command("git", "stash", "push", "-m", "gitsyncer-auto-stash").Run(); err != nil {
+ return fmt.Errorf("failed to stash changes: %w", err)
+ }
+ defer func() {
+ // Try to pop the stash at the end
+ exec.Command("git", "stash", "pop").Run()
+ }()
+ }
+
// Create or checkout the branch
if err := s.checkoutBranch(branch); err != nil {
return fmt.Errorf("failed to checkout branch %s: %w", branch, err)
@@ -333,9 +362,14 @@ func (s *Syncer) syncBranch(branch string, remotes map[string]*config.Organizati
func (s *Syncer) checkoutBranch(branch string) error {
// First try to checkout existing branch
cmd := exec.Command("git", "checkout", branch)
- if err := cmd.Run(); err == nil {
+ output, err := cmd.CombinedOutput()
+ if err == nil {
return nil
}
+
+ // If checkout failed, check the error
+ outputStr := string(output)
+ fmt.Printf(" Initial checkout failed: %s\n", strings.TrimSpace(outputStr))
// If that fails, create a new branch tracking the first remote that has it
for i := range s.config.Organizations {
@@ -344,7 +378,11 @@ func (s *Syncer) checkoutBranch(branch string) error {
if s.remoteBranchExists(remoteName, branch) {
cmd = exec.Command("git", "checkout", "-b", branch, fmt.Sprintf("%s/%s", remoteName, branch))
- return cmd.Run()
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return fmt.Errorf("failed to create tracking branch: %s", string(output))
+ }
+ return nil
}
}