From 7acf19a812ce8bfef7bd9ec48639183d57a2dc99 Mon Sep 17 00:00:00 2001 From: Bart Jaskulski Date: Thu, 19 May 2022 13:54:35 +0200 Subject: [PATCH 1/4] Locate root worktree path in git worktree --- src/Locator/GitRepositoryDirLocator.php | 14 +++++++++++++- test/Unit/Locator/GitRepositoryDirLocatorTest.php | 9 ++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Locator/GitRepositoryDirLocator.php b/src/Locator/GitRepositoryDirLocator.php index c40c2962..f5ed08fc 100644 --- a/src/Locator/GitRepositoryDirLocator.php +++ b/src/Locator/GitRepositoryDirLocator.php @@ -4,7 +4,10 @@ namespace GrumPHP\Locator; +use GrumPHP\Exception\RuntimeException; use GrumPHP\Util\Filesystem; +use Symfony\Component\Finder\Finder; +use Symfony\Component\Finder\SplFileInfo; class GitRepositoryDirLocator { @@ -36,7 +39,16 @@ public function locate(string $gitDir): string $gitRepositoryDir = $matches[1]; if ($this->filesystem->isAbsolutePath($gitRepositoryDir)) { - return $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 . '/commondir')); + return $this->filesystem->realpath( + $this->filesystem->makePathAbsolute( + $worktreeRelativeRoot, + $gitRepositoryDir + ) + ); } return $this->filesystem->buildPath( diff --git a/test/Unit/Locator/GitRepositoryDirLocatorTest.php b/test/Unit/Locator/GitRepositoryDirLocatorTest.php index 00f6872f..f49caa92 100644 --- a/test/Unit/Locator/GitRepositoryDirLocatorTest.php +++ b/test/Unit/Locator/GitRepositoryDirLocatorTest.php @@ -31,7 +31,7 @@ protected function setUp(): void $this->filesystem = new Filesystem(); $this->locator = new GitRepositoryDirLocator($this->filesystem); - $this->gitDir = $this->workspace . DIRECTORY_SEPARATOR . '.git'; + $this->gitDir = $this->workspace . DIRECTORY_SEPARATOR . '.git'; } /** @@ -69,7 +69,10 @@ public function it_can_passthrough_git_dir_path_if_file_is_not_parseable(): void */ public function it_can_locate_git_dir_in_workspaces(): void { - $this->filesystem->dumpFile($this->gitDir, 'gitdir: /dev/null'); - $this->assertEquals('/dev/null', $this->locator->locate($this->gitDir)); + $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.'/git_root', $this->locator->locate($this->gitDir)); } } From 4bc18717cd62d5260e9104ce7a3d831a7bca0ae7 Mon Sep 17 00:00:00 2001 From: Bart Jaskulski Date: Thu, 19 May 2022 14:01:40 +0200 Subject: [PATCH 2/4] Normalize usage of DIRECTORY_SEPARATOR constant --- src/Locator/GitRepositoryDirLocator.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Locator/GitRepositoryDirLocator.php b/src/Locator/GitRepositoryDirLocator.php index f5ed08fc..76a1ec8f 100644 --- a/src/Locator/GitRepositoryDirLocator.php +++ b/src/Locator/GitRepositoryDirLocator.php @@ -39,10 +39,16 @@ public function locate(string $gitDir): string $gitRepositoryDir = $matches[1]; if ($this->filesystem->isAbsolutePath($gitRepositoryDir)) { - if (!$this->filesystem->isFile($gitRepositoryDir . DIRECTORY_SEPARATOR . 'commondir')) { + 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 . '/commondir')); + + $worktreeRelativeRoot = trim( + $this->filesystem->readPath( + $gitRepositoryDir.DIRECTORY_SEPARATOR.'commondir' + ) + ); + return $this->filesystem->realpath( $this->filesystem->makePathAbsolute( $worktreeRelativeRoot, From caabb1d722f7633730557edebbb2dc48098ec5f8 Mon Sep 17 00:00:00 2001 From: Bart Jaskulski Date: Fri, 20 May 2022 00:05:59 +0200 Subject: [PATCH 3/4] Fix test failing in Windows environment --- test/Unit/Locator/GitRepositoryDirLocatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Unit/Locator/GitRepositoryDirLocatorTest.php b/test/Unit/Locator/GitRepositoryDirLocatorTest.php index f49caa92..d30e1629 100644 --- a/test/Unit/Locator/GitRepositoryDirLocatorTest.php +++ b/test/Unit/Locator/GitRepositoryDirLocatorTest.php @@ -73,6 +73,6 @@ public function it_can_locate_git_dir_in_workspaces(): void 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.'/git_root', $this->locator->locate($this->gitDir)); + $this->assertEquals($this->workspace.DIRECTORY_SEPARATOR.'git_root', $this->locator->locate($this->gitDir)); } } From 21b9a55ccbee42b2b2cf1f4d4051c87cb37d82ae Mon Sep 17 00:00:00 2001 From: Bart Jaskulski Date: Fri, 29 Nov 2024 14:52:32 +0100 Subject: [PATCH 4/4] Clarify git worktree handling Signed-off-by: Bart Jaskulski --- src/Locator/GitRepositoryDirLocator.php | 64 +++++++++++++------ .../Locator/GitRepositoryDirLocatorTest.php | 11 ++-- 2 files changed, 50 insertions(+), 25 deletions(-) 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)); } }