1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-26 00:32:41 +01:00

Improve performance of arc branch in Git with many branches

Summary:
This is mostly just a personal quality-of-life fix. I run this command fairly often and having it return a little faster is nice.

This replaces a `git show` for each individual branch with a big `git for-each-ref` which we were already running anyway. This is quite a bit faster.

This command also occasionally hangs or segfaults for me while executing the huge pile of subprocesses. This is unreliable to reproduce, probably some bug in some PHP extension I have, and likely hard to narrow down, and this approach is better in every way anyway.

Test Plan:
  - Ran `arc branch` in Git, observed faster output (in my `phabricator/`, about 2000ms -> 1200ms).
  - Ran `arc feature` in Mercurial.

Reviewers: chad

Reviewed By: chad

Differential Revision: https://secure.phabricator.com/D15735
This commit is contained in:
epriestley 2016-04-16 09:38:17 -07:00
parent 737f5c0df9
commit a2ab38df78
2 changed files with 59 additions and 31 deletions

View file

@ -966,19 +966,43 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
* @return list<dict<string, string>> Dictionary of branch information.
*/
public function getAllBranches() {
list($ref_list) = $this->execxLocal(
'for-each-ref --format=%s refs/heads',
'%(refname)');
$refs = explode("\n", rtrim($ref_list));
$field_list = array(
'%(refname)',
'%(objectname)',
'%(committerdate:raw)',
'%(tree)',
'%(subject)',
'%(subject)%0a%0a%(body)',
'%02',
);
list($stdout) = $this->execxLocal(
'for-each-ref --format=%s -- refs/heads',
implode('%01', $field_list));
$current = $this->getBranchName();
$result = array();
foreach ($refs as $ref) {
$lines = explode("\2", $stdout);
foreach ($lines as $line) {
$line = trim($line);
if (!strlen($line)) {
continue;
}
$fields = explode("\1", $line, 6);
list($ref, $hash, $epoch, $tree, $desc, $text) = $fields;
$branch = $this->getBranchNameFromRef($ref);
if ($branch) {
$result[] = array(
'current' => ($branch === $current),
'name' => $branch,
'hash' => $hash,
'tree' => $tree,
'epoch' => (int)$epoch,
'desc' => $desc,
'text' => $text,
);
}
}

View file

@ -174,38 +174,37 @@ EOTEXT
private function loadCommitInfo(array $branches) {
$repository_api = $this->getRepositoryAPI();
$branches = ipull($branches, null, 'name');
if ($repository_api instanceof ArcanistMercurialAPI) {
$futures = array();
foreach ($branches as $branch) {
if ($repository_api instanceof ArcanistMercurialAPI) {
$futures[$branch['name']] = $repository_api->execFutureLocal(
'log -l 1 --template %s -r %s',
"{node}\1{date|hgdate}\1{p1node}\1{desc|firstline}\1{desc}",
hgsprintf('%s', $branch['name']));
} else {
// NOTE: "-s" is an option deep in git's diff argument parser that
// doesn't seem to have much documentation and has no long form. It
// suppresses any diff output.
$futures[$branch['name']] = $repository_api->execFutureLocal(
'show -s --format=%C %s --',
'%H%x01%ct%x01%T%x01%s%x01%s%n%n%b',
$branch['name']);
}
}
$branches = ipull($branches, null, 'name');
$futures = id(new FutureIterator($futures))
->limit(16);
foreach ($futures as $name => $future) {
list($info) = $future->resolvex();
list($hash, $epoch, $tree, $desc, $text) = explode("\1", trim($info), 5);
$branch = $branches[$name] + array(
$fields = explode("\1", trim($info), 5);
list($hash, $epoch, $tree, $desc, $text) = $fields;
$branches[$name] += array(
'hash' => $hash,
'desc' => $desc,
'tree' => $tree,
'epoch' => (int)$epoch,
'text' => $text,
);
}
}
foreach ($branches as $name => $branch) {
$text = $branch['text'];
try {
$message = ArcanistDifferentialCommitMessage::newFromRawCorpus($text);
@ -332,6 +331,11 @@ EOTEXT
);
}
if (!$out) {
// All of the revisions are closed or abandoned.
return;
}
$len_name = max(array_map('strlen', ipull($out, 'name'))) + 2;
$len_status = max(array_map('strlen', ipull($out, 'status'))) + 2;