Skip to content

Commit 4d8c63f

Browse files
authored
Fix render --reset=false not fast-forwarding existing branches to latest remote (#24)
1 parent 014a53a commit 4d8c63f

2 files changed

Lines changed: 69 additions & 2 deletions

File tree

internal/workspace/workspace.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,10 @@ func (s *Service) createWorktree(ctx context.Context, rc *repoRenderContext, opt
363363
if err := s.Git.AddWorktree(ctx, rc.barePath, rc.worktreePath, rc.repo.Branch); err != nil {
364364
return fmt.Errorf("creating worktree for %s: %w", rc.repo.URL, err)
365365
}
366-
progress(fmt.Sprintf(" └── %s (%s) ✓", rc.repoPath, rc.repo.Branch))
367-
return nil
366+
// Fast-forward to latest remote state — the local branch ref may be
367+
// stale if another worktree has this branch checked out (git skips
368+
// updating checked-out branches during fetch).
369+
return s.updateWorktreeRemote(ctx, rc, progress)
368370
}
369371

370372
baseBranch, err := s.resolveBaseBranch(ctx, rc)

internal/workspace/workspace_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -976,6 +976,71 @@ func TestRenderCreatesClaudeFiles(t *testing.T) {
976976
}
977977
}
978978

979+
func TestRenderExistingBranchUpdatesToRemote(t *testing.T) {
980+
svc, mock := testService(t)
981+
ctx := context.Background()
982+
983+
st := state.NewState("Existing branch update", "Existing branch should fast-forward to remote", []state.Repo{
984+
{URL: "github.com/org/repo", Branch: "staging", Path: "./repo"},
985+
})
986+
if err := svc.Create("existing-branch", st); err != nil {
987+
t.Fatal(err)
988+
}
989+
990+
// Branch exists remotely; worktree is clean after creation
991+
mock.branchExists = true
992+
mock.isClean = true
993+
994+
var messages []string
995+
err := svc.Render(ctx, "existing-branch", func(msg string) { messages = append(messages, msg) }, &RenderOptions{
996+
OnBranchConflict: BranchConflictUseExisting,
997+
})
998+
if err != nil {
999+
t.Fatalf("Render: %v", err)
1000+
}
1001+
1002+
// Should have created the worktree
1003+
if len(mock.worktrees) != 1 {
1004+
t.Fatalf("worktrees = %d, want 1", len(mock.worktrees))
1005+
}
1006+
1007+
// Should have called EnsureRemoteRef for the branch to update to latest
1008+
foundRef := false
1009+
for _, ref := range mock.remoteRefs {
1010+
if ref == "staging" {
1011+
foundRef = true
1012+
break
1013+
}
1014+
}
1015+
if !foundRef {
1016+
t.Errorf("remoteRefs = %v, want to contain 'staging'", mock.remoteRefs)
1017+
}
1018+
1019+
// Should have called ResetBranch to fast-forward to origin/staging
1020+
foundReset := false
1021+
for _, ref := range mock.resets {
1022+
if ref == "origin/staging" {
1023+
foundReset = true
1024+
break
1025+
}
1026+
}
1027+
if !foundReset {
1028+
t.Errorf("resets = %v, want to contain 'origin/staging'", mock.resets)
1029+
}
1030+
1031+
// Progress should show "updated"
1032+
found := false
1033+
for _, msg := range messages {
1034+
if strings.Contains(msg, "updated") {
1035+
found = true
1036+
break
1037+
}
1038+
}
1039+
if !found {
1040+
t.Errorf("expected progress message with 'updated', got %v", messages)
1041+
}
1042+
}
1043+
9791044
func TestRenderBranchSwitchExistingBranch(t *testing.T) {
9801045
svc, mock := testService(t)
9811046
ctx := context.Background()

0 commit comments

Comments
 (0)