diff --git a/src/Gitonomy/Git/Reference/Branch.php b/src/Gitonomy/Git/Reference/Branch.php index 0f263a7..0d27fb8 100644 --- a/src/Gitonomy/Git/Reference/Branch.php +++ b/src/Gitonomy/Git/Reference/Branch.php @@ -12,8 +12,10 @@ namespace Gitonomy\Git\Reference; +use Gitonomy\Git\Exception\ProcessException; use Gitonomy\Git\Exception\RuntimeException; use Gitonomy\Git\Reference; +use Gitonomy\Git\Util\StringHelper; /** * Representation of a branch reference. @@ -53,6 +55,49 @@ public function isLocal() return $this->local; } + /** + * Check if this branch is merged to a destination branch + * Optionally, check only with remote branches. + * + * @param string $destinationBranchName + * @param bool $compareOnlyWithRemote + * + * @return null|bool + */ + public function isMergedTo($destinationBranchName = 'master', $compareOnlyWithRemote = false) + { + $arguments = ['-a']; + + if ($compareOnlyWithRemote) { + $arguments = ['-r']; + } + + $arguments[] = '--merged'; + $arguments[] = $destinationBranchName; + + try { + $result = $this->repository->run('branch', $arguments); + } catch (ProcessException $e) { + throw new RuntimeException( + sprintf('Cannot determine if merged to the branch "%s"', $destinationBranchName), + $e->getCode(), + $e + ); + } + + if (!$result) { + return false; + } + + $output = explode("\n", trim(str_replace(['*', 'remotes/'], '', $result))); + $filtered_output = array_filter($output, static function ($v) { + return false === StringHelper::strpos($v, '->'); + }); + $trimmed_output = array_map('trim', $filtered_output); + + return in_array($this->getName(), $trimmed_output, true); + } + private function detectBranchType() { if (null === $this->local) { diff --git a/tests/Gitonomy/Git/Tests/ReferenceTest.php b/tests/Gitonomy/Git/Tests/ReferenceTest.php index d24a5e6..0f97557 100644 --- a/tests/Gitonomy/Git/Tests/ReferenceTest.php +++ b/tests/Gitonomy/Git/Tests/ReferenceTest.php @@ -209,4 +209,32 @@ public function testCreateAndDeleteBranch($repository) $branch->delete(); $this->assertFalse($references->hasBranch('foobar'), 'Branch foobar removed'); } + + /** + * @dataProvider provideFoobar + */ + public function testIsBranchMergedToMaster() + { + $repository = self::createFoobarRepository(false); + + $repository->run('config', ['--local', 'user.name', '"Unit Test"']); + $repository->run('config', ['--local', 'user.email', '"unit_test@unit-test.com"']); + + $master = $repository->getReferences()->getBranch('master'); + $references = $repository->getReferences(); + + $branch = $references->createBranch('foobar-new', $master->getCommit()->getHash()); + + $this->assertTrue($branch->isMergedTo('master')); + + $wc = $repository->getWorkingCopy(); + $wc->checkout('foobar-new'); + + $file = $repository->getWorkingDir().'/foobar-test.txt'; + file_put_contents($file, 'test'); + $repository->run('add', [$file]); + $repository->run('commit', ['-m', 'foobar-test.txt updated']); + + $this->assertFalse($branch->isMergedTo('master')); + } }