From 21c15c2290d0323bae3268b5148a3ae73a035f31 Mon Sep 17 00:00:00 2001 From: eshulman2 Date: Sun, 26 Jul 2026 08:45:08 +0300 Subject: [PATCH] fix: skip rebase before first branch push --- src/forge/workspace/git_ops.py | 7 ++++ tests/unit/workspace/test_git_ops_sync.py | 49 +++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tests/unit/workspace/test_git_ops_sync.py diff --git a/src/forge/workspace/git_ops.py b/src/forge/workspace/git_ops.py index c78a1a78..6c8f8a7a 100644 --- a/src/forge/workspace/git_ops.py +++ b/src/forge/workspace/git_ops.py @@ -131,6 +131,13 @@ def pull_rebase(self, remote: str = "fork") -> None: branch = self.workspace.branch_name logger.info(f"Syncing with {remote}/{branch} before implementing changes") self._run_git("fetch", remote) + if not self.remote_branch_exists(branch, remote=remote): + logger.info( + "Remote branch %s/%s does not exist yet; skipping rebase before first push", + remote, + branch, + ) + return self._run_git("rebase", f"{remote}/{branch}") logger.info(f"Rebase onto {remote}/{branch} complete") diff --git a/tests/unit/workspace/test_git_ops_sync.py b/tests/unit/workspace/test_git_ops_sync.py new file mode 100644 index 00000000..27815b94 --- /dev/null +++ b/tests/unit/workspace/test_git_ops_sync.py @@ -0,0 +1,49 @@ +"""Tests for synchronizing implementation workspaces with remote branches.""" + +from pathlib import Path +from unittest.mock import MagicMock, call, patch + +from forge.workspace.git_ops import GitOperations +from forge.workspace.manager import Workspace + + +def _git_ops(tmp_path: Path) -> GitOperations: + workspace = Workspace( + path=tmp_path / "repo", + repo_name="org/repo", + branch_name="forge/test-123", + ticket_key="TEST-123", + ) + with patch("forge.workspace.git_ops.get_settings", return_value=MagicMock()): + return GitOperations(workspace) + + +def test_pull_rebase_skips_missing_remote_branch_before_first_push(tmp_path): + """A new implementation branch is local-only until its first backup push.""" + git = _git_ops(tmp_path) + + with ( + patch.object(git, "_run_git") as run_git, + patch.object(git, "remote_branch_exists", return_value=False) as branch_exists, + ): + git.pull_rebase(remote="origin") + + run_git.assert_called_once_with("fetch", "origin") + branch_exists.assert_called_once_with("forge/test-123", remote="origin") + + +def test_pull_rebase_rebases_when_remote_branch_exists(tmp_path): + """Existing backup branches are still incorporated before implementation.""" + git = _git_ops(tmp_path) + + with ( + patch.object(git, "_run_git") as run_git, + patch.object(git, "remote_branch_exists", return_value=True) as branch_exists, + ): + git.pull_rebase(remote="fork") + + assert run_git.call_args_list == [ + call("fetch", "fork"), + call("rebase", "fork/forge/test-123"), + ] + branch_exists.assert_called_once_with("forge/test-123", remote="fork")