From 6f9e18a1cec6543160a2ad54bdee06c3efff7297 Mon Sep 17 00:00:00 2001 From: Jonatan Dahl Date: Wed, 28 Jan 2026 19:19:17 -0500 Subject: [PATCH 1/2] feat: fast-forward main when no stack branches --- cmd/sync.go | 10 ++++++++++ cmd/sync_test.go | 1 + internal/git/git.go | 11 +++++++++++ internal/git/interface.go | 1 + internal/testutil/mocks.go | 5 +++++ 5 files changed, 28 insertions(+) diff --git a/cmd/sync.go b/cmd/sync.go index f2ba742..c02971d 100644 --- a/cmd/sync.go +++ b/cmd/sync.go @@ -314,7 +314,17 @@ func runSync(gitClient git.GitClient, githubClient github.GitHubClient) error { if len(chain) == 0 { // Wait for parallel operations before returning wg.Wait() + if fetchErr != nil { + return fmt.Errorf("failed to fetch: %w", fetchErr) + } fmt.Println("No stack branches found.") + if originalBranch == baseBranch { + fmt.Printf("Updating %s from origin...\n", ui.Branch(baseBranch)) + if err := gitClient.FastForwardToRemote(baseBranch); err != nil { + return fmt.Errorf("failed to update %s: %w", baseBranch, err) + } + fmt.Println(ui.Success(fmt.Sprintf("Updated %s", ui.Branch(baseBranch)))) + } return nil } diff --git a/cmd/sync_test.go b/cmd/sync_test.go index 906fcc0..96735ec 100644 --- a/cmd/sync_test.go +++ b/cmd/sync_test.go @@ -494,6 +494,7 @@ func TestRunSyncNoStackBranches(t *testing.T) { // These are started but may not complete before early return mockGit.On("Fetch").Return(nil).Maybe() mockGH.On("GetAllPRs").Return(make(map[string]*github.PRInfo), nil).Maybe() + mockGit.On("FastForwardToRemote", "main").Return(nil).Maybe() // These calls don't happen when there are no stack branches (early return) diff --git a/internal/git/git.go b/internal/git/git.go index a3699f9..9e537ed 100644 --- a/internal/git/git.go +++ b/internal/git/git.go @@ -273,6 +273,17 @@ func (c *gitClient) Fetch() error { return err } +// FastForwardToRemote fast-forwards the current branch to match origin/ +func (c *gitClient) FastForwardToRemote(branch string) error { + remoteBranch := "origin/" + branch + if DryRun { + fmt.Printf(" [DRY RUN] git merge --ff-only %s\n", remoteBranch) + return nil + } + _, err := c.runCmd("merge", "--ff-only", remoteBranch) + return err +} + // BranchExists checks if a branch exists locally func (c *gitClient) BranchExists(name string) bool { output := c.runCmdMayFail("rev-parse", "--verify", "refs/heads/"+name) diff --git a/internal/git/interface.go b/internal/git/interface.go index fb36b95..6fdafde 100644 --- a/internal/git/interface.go +++ b/internal/git/interface.go @@ -21,6 +21,7 @@ type GitClient interface { ForcePush(branch string) error IsWorkingTreeClean() (bool, error) Fetch() error + FastForwardToRemote(branch string) error BranchExists(name string) bool RemoteBranchExists(name string) bool GetRemoteBranchesSet() map[string]bool diff --git a/internal/testutil/mocks.go b/internal/testutil/mocks.go index fe28f3a..2938279 100644 --- a/internal/testutil/mocks.go +++ b/internal/testutil/mocks.go @@ -105,6 +105,11 @@ func (m *MockGitClient) Fetch() error { return args.Error(0) } +func (m *MockGitClient) FastForwardToRemote(branch string) error { + args := m.Called(branch) + return args.Error(0) +} + func (m *MockGitClient) BranchExists(name string) bool { args := m.Called(name) return args.Bool(0) From 078a36987d79670c3c9abdf40a7b4bf3d18aa44f Mon Sep 17 00:00:00 2001 From: Jonatan Dahl Date: Wed, 28 Jan 2026 19:23:21 -0500 Subject: [PATCH 2/2] fix: clarify status message when on base branch --- cmd/status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/status.go b/cmd/status.go index 5ec91d1..ddf791c 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -185,7 +185,7 @@ func runStatus(gitClient git.GitClient, githubClient github.GitHubClient) error // Don't offer to add the base branch to a stack - it can't have a parent if currentBranch == baseBranch { - fmt.Printf("Branch '%s' is the base branch and cannot be part of a stack.\n", ui.Branch(currentBranch)) + fmt.Printf("No stack found. You're on the base branch (%s).\n", ui.Branch(currentBranch)) fmt.Printf("\nUse '%s' to create a new stack branch.\n", ui.Command("stack new ")) return nil }