diff --git a/apps/api/src/utils/git_control.py b/apps/api/src/utils/git_control.py index becebc1..92e57ba 100644 --- a/apps/api/src/utils/git_control.py +++ b/apps/api/src/utils/git_control.py @@ -124,7 +124,15 @@ def create_branch(repo_path: str, name: str, base_branch: str = "HEAD") -> None: try: _run_git_command(repo_path, "rev-parse", "--verify", "HEAD^{commit}") except RuntimeError: - _run_git_command(repo_path, "checkout", "--orphan", name) + # No commits yet - empty repository + try: + _run_git_command(repo_path, "checkout", "--orphan", name) + except RuntimeError as e: + if "work tree" in str(e).lower(): + # Bare repository - use symbolic-ref instead + _run_git_command(repo_path, "symbolic-ref", "HEAD", f"refs/heads/{name}") + return + raise return _run_git_command(repo_path, "branch", name, base_branch) @@ -155,7 +163,14 @@ def checkout_branch(repo_path: str, name: str) -> None: Raises: RuntimeError: If checkout fails """ - _run_git_command(repo_path, "checkout", name) + try: + _run_git_command(repo_path, "checkout", name) + except RuntimeError as e: + if "work tree" in str(e).lower(): + # Bare repository - use symbolic-ref instead + _run_git_command(repo_path, "symbolic-ref", "HEAD", f"refs/heads/{name}") + return + raise def commit_changes( @@ -290,6 +305,10 @@ def get_current_branch(repo_path: str) -> str: Current branch name """ try: - return _run_git_command(repo_path, "rev-parse", "--abbrev-ref", "HEAD").strip() + branch = _run_git_command(repo_path, "rev-parse", "--abbrev-ref", "HEAD").strip() + if branch != "HEAD": + return branch except RuntimeError: - return _run_git_command(repo_path, "symbolic-ref", "--short", "HEAD").strip() + pass + + return _run_git_command(repo_path, "symbolic-ref", "--short", "HEAD").strip() diff --git a/apps/api/tests/integration/test_git_control.py b/apps/api/tests/integration/test_git_control.py index a7ab139..37d5425 100644 --- a/apps/api/tests/integration/test_git_control.py +++ b/apps/api/tests/integration/test_git_control.py @@ -70,6 +70,20 @@ def test_get_current_branch_handles_unborn_main() -> None: assert get_current_branch(tmpdir) == "main" +def test_create_branch_on_bare_repo_with_no_commits() -> None: + with tempfile.TemporaryDirectory() as tmpdir: + os.system(f"git init --bare {tmpdir}/bare.git >/dev/null 2>&1") + create_branch(f"{tmpdir}/bare.git", "main") + assert get_current_branch(f"{tmpdir}/bare.git") == "main" + + +def test_checkout_branch_on_bare_repo_with_no_commits() -> None: + with tempfile.TemporaryDirectory() as tmpdir: + os.system(f"git init --bare {tmpdir}/bare.git >/dev/null 2>&1") + checkout_branch(f"{tmpdir}/bare.git", "main") + assert get_current_branch(f"{tmpdir}/bare.git") == "main" + + class TestBranchOperations: """Tests for branch management functions."""