getRequest(); $repository = $drequest->getRepository(); // We need to add 1 in case we pick up HEAD. $count = $this->getOffset() + $this->getLimit() + 1; list($stdout) = $repository->execxLocalCommand( 'for-each-ref %C --sort=-creatordate --format=%s refs/remotes', $count ? '--count='.(int)$count : null, '%(refname:short) %(objectname)'); $branch_list = self::parseGitRemoteBranchOutput( $stdout, $only_this_remote = DiffusionBranchInformation::DEFAULT_GIT_REMOTE); $branches = array(); foreach ($branch_list as $name => $head) { if (!$repository->shouldTrackBranch($name)) { continue; } $branch = new DiffusionBranchInformation(); $branch->setName($name); $branch->setHeadCommitIdentifier($head); $branches[] = $branch; } $offset = $this->getOffset(); if ($offset) { $branches = array_slice($branches, $offset); } // We might have too many even after offset slicing, if there was no HEAD // for some reason. $limit = $this->getLimit(); if ($limit) { $branches = array_slice($branches, 0, $limit); } return $branches; } /** * Parse the output of 'git branch -r --verbose --no-abbrev' or similar into * a map. For instance: * * array( * 'origin/master' => '99a9c082f9a1b68c7264e26b9e552484a5ae5f25', * ); * * If you specify $only_this_remote, branches will be filtered to only those * on the given remote, **and the remote name will be stripped**. For example: * * array( * 'master' => '99a9c082f9a1b68c7264e26b9e552484a5ae5f25', * ); * * @param string stdout of git branch command. * @param string Filter branches to those on a specific remote. * @return map Map of 'branch' or 'remote/branch' to hash at HEAD. */ public static function parseGitRemoteBranchOutput( $stdout, $only_this_remote = null) { $map = array(); $lines = array_filter(explode("\n", $stdout)); foreach ($lines as $line) { $matches = null; if (preg_match('/^ (\S+)\s+-> (\S+)$/', $line, $matches)) { // This is a line like: // // origin/HEAD -> origin/master // // ...which we don't currently do anything interesting with, although // in theory we could use it to automatically choose the default // branch. continue; } if (!preg_match('/^ *(\S+)\s+([a-z0-9]{40})/', $line, $matches)) { throw new Exception("Failed to parse {$line}!"); } $remote_branch = $matches[1]; $branch_head = $matches[2]; if (strpos($remote_branch, 'HEAD') !== false) { // let's assume that no one will call their remote or branch HEAD continue; } if ($only_this_remote) { $matches = null; if (!preg_match('#^([^/]+)/(.*)$#', $remote_branch, $matches)) { throw new Exception( "Failed to parse remote branch '{$remote_branch}'!"); } $remote_name = $matches[1]; $branch_name = $matches[2]; if ($remote_name != $only_this_remote) { continue; } $map[$branch_name] = $branch_head; } else { $map[$remote_branch] = $branch_head; } } return $map; } }