diff --git a/apps/api/src/utils/git_control.py b/apps/api/src/utils/git_control.py index a5ea7ea..59a6874 100644 --- a/apps/api/src/utils/git_control.py +++ b/apps/api/src/utils/git_control.py @@ -121,6 +121,13 @@ def create_branch(repo_path: str, name: str, base_branch: str = "HEAD") -> None: Raises: RuntimeError: If branch creation fails """ + if base_branch == "HEAD": + try: + _run_git_command(repo_path, "rev-parse", "--verify", "HEAD") + except RuntimeError: + _run_git_command(repo_path, "checkout", "--orphan", name) + return + _run_git_command(repo_path, "branch", name, base_branch) diff --git a/apps/api/tests/unit/test_git_repository_working_clones.py b/apps/api/tests/unit/test_git_repository_working_clones.py index de93166..1fdd2cb 100644 --- a/apps/api/tests/unit/test_git_repository_working_clones.py +++ b/apps/api/tests/unit/test_git_repository_working_clones.py @@ -4,6 +4,7 @@ import pytest from fastapi import HTTPException from src.api.git_repositories import _clone_working_repository, _init_working_repository +from src.utils.git_control import create_branch def test_clone_working_repository_uses_normal_clone() -> None: @@ -44,3 +45,14 @@ def test_init_working_repository_falls_back_to_symbolic_ref() -> None: assert run_mock.call_args_list[0].args[0] == ["git", "init", "-b", "main", "/tmp/new-repo"] assert run_mock.call_args_list[1].args[0] == ["git", "init", "/tmp/new-repo"] assert run_mock.call_args_list[2].args[0] == ["git", "-C", "/tmp/new-repo", "symbolic-ref", "HEAD", "refs/heads/main"] + + +def test_create_branch_uses_orphan_checkout_when_head_is_unborn() -> None: + verify_head = Mock(returncode=128, stderr="fatal: Needed a single revision") + checkout_orphan = Mock(returncode=0, stderr="") + + with patch("src.utils.git_control._run_git_command", side_effect=[verify_head, checkout_orphan]) as run_mock: + create_branch("/tmp/new-repo", "feature/test") + + assert run_mock.call_args_list[0].args[1:] == ("rev-parse", "--verify", "HEAD") + assert run_mock.call_args_list[1].args[1:] == ("checkout", "--orphan", "feature/test") diff --git a/apps/web/src/components/git-toolbar.tsx b/apps/web/src/components/git-toolbar.tsx index 9ef5f39..31a8f07 100644 --- a/apps/web/src/components/git-toolbar.tsx +++ b/apps/web/src/components/git-toolbar.tsx @@ -112,7 +112,7 @@ export const GitToolbar = ({ if (!newBranchName.trim()) return; setLoading(true); try { - await createBranch(projectId, repoId, newBranchName, newBranchBase || "HEAD"); + await createBranch(projectId, repoId, newBranchName, newBranchBase || currentBranch || "HEAD"); setShowNewBranch(false); setNewBranchName(""); setNewBranchBase(""); @@ -131,6 +131,8 @@ export const GitToolbar = ({ status.untracked.length > 0 ); + const canSync = hasRemote; + return (