diff --git a/src/Locator/GitRepositoryDirLocator.php b/src/Locator/GitRepositoryDirLocator.php index 76a1ec8f..32ea7641 100644 --- a/src/Locator/GitRepositoryDirLocator.php +++ b/src/Locator/GitRepositoryDirLocator.php @@ -4,10 +4,7 @@ namespace GrumPHP\Locator; -use GrumPHP\Exception\RuntimeException; use GrumPHP\Util\Filesystem; -use Symfony\Component\Finder\Finder; -use Symfony\Component\Finder\SplFileInfo; class GitRepositoryDirLocator { @@ -38,23 +35,8 @@ public function locate(string $gitDir): string $gitRepositoryDir = $matches[1]; - if ($this->filesystem->isAbsolutePath($gitRepositoryDir)) { - if (!$this->filesystem->isFile($gitRepositoryDir.DIRECTORY_SEPARATOR.'commondir')) { - throw new RuntimeException('The git directory for worktree could not be found.'); - } - - $worktreeRelativeRoot = trim( - $this->filesystem->readPath( - $gitRepositoryDir.DIRECTORY_SEPARATOR.'commondir' - ) - ); - - return $this->filesystem->realpath( - $this->filesystem->makePathAbsolute( - $worktreeRelativeRoot, - $gitRepositoryDir - ) - ); + if ($this->isWorktree($gitRepositoryDir)) { + return $this->locateWorktreeRoot($gitRepositoryDir); } return $this->filesystem->buildPath( @@ -62,4 +44,46 @@ public function locate(string $gitDir): string $gitRepositoryDir ); } + + /** + * If a given path (from gitdir value) is absolute and there is a commondir file, it is + * a worktree. + */ + private function isWorktree(string $gitDir): bool + { + return $this->filesystem->isAbsolutePath($gitDir) + && $this->filesystem->isFile($gitDir.DIRECTORY_SEPARATOR.'commondir'); + } + + /** + * Retreiving repository dir for worktree nominally returns path to the configured worktree, + * which does not hold hooks. We need to resolve the actual repository root. + * + * Example directory structure: + * ``` + * /project + * .git/ + * .git/hooks/ + * .git/worktrees/ + * worktree1 + * commondir: relative path to /project/.git + * /worktree1 + * .git: file with path to /project/.git/worktrees/worktree1 + * ``` + */ + private function locateWorktreeRoot(string $gitRepositoryDir): string + { + $worktreeRelativeRoot = trim( + $this->filesystem->readPath( + $gitRepositoryDir.DIRECTORY_SEPARATOR.'commondir' + ) + ); + + return $this->filesystem->realpath( + $this->filesystem->makePathAbsolute( + $worktreeRelativeRoot, + $gitRepositoryDir + ) + ); + } } diff --git a/test/Unit/Locator/GitRepositoryDirLocatorTest.php b/test/Unit/Locator/GitRepositoryDirLocatorTest.php index d30e1629..789a5642 100644 --- a/test/Unit/Locator/GitRepositoryDirLocatorTest.php +++ b/test/Unit/Locator/GitRepositoryDirLocatorTest.php @@ -69,10 +69,11 @@ public function it_can_passthrough_git_dir_path_if_file_is_not_parseable(): void */ public function it_can_locate_git_dir_in_workspaces(): void { - $worktreeRoot = $this->workspace.'/git_root/worktrees/git_worktree/'; - mkdir($worktreeRoot, 0777, true); - $this->filesystem->dumpFile($worktreeRoot.'/commondir', '../..'); - $this->filesystem->dumpFile($this->gitDir, 'gitdir: '.$this->workspace.'/git_root/worktrees/git_worktree'); - $this->assertEquals($this->workspace.DIRECTORY_SEPARATOR.'git_root', $this->locator->locate($this->gitDir)); + $ourWorktreeProject = $this->workspace.'/project1/'; + $worktreeGitRoot = $this->gitDir.'/worktrees/worktree1/'; + mkdir($worktreeGitRoot, 0777, true); + $this->filesystem->dumpFile($worktreeGitRoot.'/commondir', '../..'); + $this->filesystem->dumpFile($ourWorktreeProject.'/.git', 'gitdir: '.$this->gitDir.'/worktrees/worktree1'); + $this->assertEquals($this->gitDir, $this->locator->locate($this->gitDir)); } }