mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-27 01:02:42 +01:00
Allow repo updates to recover after force push + garbage collection
Summary: Fixes T5839. If a repository has been force pushed and garbage collected, we might have a ref cursor in the database which still points at the old commit (which no longer exists). We'll then run a command like `git log <new hash> --not <old hash>` to figure out which commits are newly pushed, and this will bomb out because `<old hash>` is invalid. Instead, validate all the `<old hash>` values before we try to make use of them. Test Plan: - Forced a repository into a bad state by mucking with the datbase, generating a reproducible failure similar to the one in T5839. - Applied patch. - `bin/repository update <callsign> --trace` filtered the bad commit and put the repository into the right state. - Saw new commits recognized correctly. - Ran `bin/repository update <callsign>` for a Mercurial and SVN repo as a sanity check. Reviewers: btrahan Reviewed By: btrahan Subscribers: epriestley Maniphest Tasks: T5839 Differential Revision: https://secure.phabricator.com/D10226
This commit is contained in:
parent
394250397e
commit
ec9eaabfbd
3 changed files with 36 additions and 6 deletions
|
@ -135,12 +135,6 @@ final class DiffusionLowLevelResolveRefsQuery
|
||||||
|
|
||||||
$futures = array();
|
$futures = array();
|
||||||
foreach ($this->refs as $ref) {
|
foreach ($this->refs as $ref) {
|
||||||
// TODO: There was a note about `--rev 'a b'` not working for branches
|
|
||||||
// with spaces in their names in older code, but I suspect this was
|
|
||||||
// misidentified and resulted from the branch name being interpeted as
|
|
||||||
// a revset. Use hgsprintf() to avoid that. If this doesn't break for a
|
|
||||||
// bit, remove this comment. Otherwise, consider `-b %s --limit 1`.
|
|
||||||
|
|
||||||
$futures[$ref] = $repository->getLocalCommandFuture(
|
$futures[$ref] = $repository->getLocalCommandFuture(
|
||||||
'log --template=%s --rev %s',
|
'log --template=%s --rev %s',
|
||||||
'{node}',
|
'{node}',
|
||||||
|
|
|
@ -63,6 +63,7 @@ final class PhabricatorRepositoryRefEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$all_closing_heads = array_unique($all_closing_heads);
|
$all_closing_heads = array_unique($all_closing_heads);
|
||||||
|
$all_closing_heads = $this->removeMissingCommits($all_closing_heads);
|
||||||
|
|
||||||
foreach ($maps as $type => $refs) {
|
foreach ($maps as $type => $refs) {
|
||||||
$cursor_group = idx($cursor_groups, $type, array());
|
$cursor_group = idx($cursor_groups, $type, array());
|
||||||
|
@ -105,6 +106,35 @@ final class PhabricatorRepositoryRefEngine
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove commits which no longer exist in the repository from a list.
|
||||||
|
*
|
||||||
|
* After a force push and garbage collection, we may have branch cursors which
|
||||||
|
* point at commits which no longer exist. This can make commands issued later
|
||||||
|
* fail. See T5839 for discussion.
|
||||||
|
*
|
||||||
|
* @param list<string> List of commit identifiers.
|
||||||
|
* @return list<string> List with nonexistent identifiers removed.
|
||||||
|
*/
|
||||||
|
private function removeMissingCommits(array $identifiers) {
|
||||||
|
if (!$identifiers) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolved = id(new DiffusionLowLevelResolveRefsQuery())
|
||||||
|
->setRepository($this->getRepository())
|
||||||
|
->withRefs($identifiers)
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
foreach ($identifiers as $key => $identifier) {
|
||||||
|
if (empty($resolved[$identifier])) {
|
||||||
|
unset($identifiers[$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $identifiers;
|
||||||
|
}
|
||||||
|
|
||||||
private function updateCursors(
|
private function updateCursors(
|
||||||
array $cursors,
|
array $cursors,
|
||||||
array $new_refs,
|
array $new_refs,
|
||||||
|
|
|
@ -42,6 +42,7 @@ final class PhabricatorRepositoryManagementUpdateWorkflow
|
||||||
|
|
||||||
public function execute(PhutilArgumentParser $args) {
|
public function execute(PhutilArgumentParser $args) {
|
||||||
$this->setVerbose($args->getArg('verbose'));
|
$this->setVerbose($args->getArg('verbose'));
|
||||||
|
$console = PhutilConsole::getConsole();
|
||||||
|
|
||||||
$repos = $this->loadRepositories($args, 'repos');
|
$repos = $this->loadRepositories($args, 'repos');
|
||||||
if (count($repos) !== 1) {
|
if (count($repos) !== 1) {
|
||||||
|
@ -103,6 +104,11 @@ final class PhabricatorRepositoryManagementUpdateWorkflow
|
||||||
|
|
||||||
$lock->unlock();
|
$lock->unlock();
|
||||||
|
|
||||||
|
$console->writeOut(
|
||||||
|
pht(
|
||||||
|
'Updated repository **%s**.',
|
||||||
|
$repository->getMonogram())."\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue