From 05d636b43215eebe1dbf49bedd4d5a36e7b8140a Mon Sep 17 00:00:00 2001 From: Pete Crocker Date: Sat, 16 May 2026 15:45:55 +0100 Subject: [PATCH] fix(repository): detect existing repo when .git is a worktree gitlink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GitRepoManager.initialize_repo() checked for `.git` with `.is_dir()`, which misses git worktrees (`.git` is a file containing `gitdir: ...`). The existing-repo branch was skipped and `Repo.init` then crashed with `FileExistsError` trying to mkdir the gitlink file. This made `infrahubctl transform` (and any other CLI relying on branch auto-detection) unusable from a worktree. Switch the check to `.exists()` — dulwich's `Repo(path)` already resolves the gitlink to the real controldir, and `porcelain.active_branch` returns the worktree's branch correctly. --- infrahub_sdk/repository.py | 3 ++- tests/unit/sdk/test_repository.py | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/infrahub_sdk/repository.py b/infrahub_sdk/repository.py index 2ad2080a..5bcd1387 100644 --- a/infrahub_sdk/repository.py +++ b/infrahub_sdk/repository.py @@ -17,7 +17,8 @@ def initialize_repo(self) -> Repo: root_path = Path(self.root_directory) - if root_path.exists() and (root_path / ".git").is_dir(): + if root_path.exists() and (root_path / ".git").exists(): + # `.git` is a directory in a regular clone and a gitlink file in a worktree. repo = Repo(self.root_directory) # Open existing repo else: repo = Repo.init(self.root_directory, default_branch=self.branch.encode("utf-8")) diff --git a/tests/unit/sdk/test_repository.py b/tests/unit/sdk/test_repository.py index 756b2e36..eca1c9a6 100644 --- a/tests/unit/sdk/test_repository.py +++ b/tests/unit/sdk/test_repository.py @@ -41,6 +41,26 @@ def test_initialize_repo_uses_existing_repo(temp_dir: str) -> None: assert (Path(temp_dir) / ".git").is_dir() +def test_initialize_repo_uses_existing_repo_in_worktree(temp_dir: str) -> None: + """A git worktree has a `.git` file (gitlink), not a directory. + + GitRepoManager must open the existing repo via the gitlink instead of trying + to re-initialize one, which would crash on `mkdir` because the file already exists. + """ + main_path = Path(temp_dir) / "main" + worktree_path = Path(temp_dir) / "worktree" + main_path.mkdir() + worktree_path.mkdir() + Repo.init(str(main_path), default_branch=b"main") + (worktree_path / ".git").write_text(f"gitdir: {main_path}/.git\n") + + manager = GitRepoManager(str(worktree_path)) + + assert manager.git is not None + assert isinstance(manager.git, Repo) + assert (worktree_path / ".git").is_file() + + def test_active_branch_returns_correct_branch(temp_dir: str) -> None: """Test that the active branch is correctly returned.""" manager = GitRepoManager(temp_dir, branch="develop")