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

Sometimes discard already-closed revisions in "arc land"

Summary:
Ref T13546. When we find commits in history which are associated with already-closed revisions, and they weren't named explicitly on the command line, and we're using a squash strategy, discard them.

This generally happens when "feature2" is on top of "feature1", but "feature1" gets amended or branched elsewhere and lands independently.

Test Plan: Ran "arc land feature3" where prior revisions had already landed, got discards on the duplicated changes.

Maniphest Tasks: T13546

Differential Revision: https://secure.phabricator.com/D21322
This commit is contained in:
epriestley 2020-06-05 12:38:26 -07:00
parent 6fb84e5164
commit 1552397c86
3 changed files with 84 additions and 12 deletions

View file

@ -7,13 +7,15 @@ final class ArcanistLandCommit
private $summary; private $summary;
private $displaySummary; private $displaySummary;
private $parents; private $parents;
private $symbols = array();
private $explicitRevisionRef; private $explicitRevisionRef;
private $revisionRef = false; private $revisionRef = false;
private $parentCommits; private $parentCommits;
private $isHeadCommit; private $isHeadCommit;
private $isImplicitCommit; private $isImplicitCommit;
private $directSymbols = array();
private $indirectSymbols = array();
public function setHash($hash) { public function setHash($hash) {
$this->hash = $hash; $this->hash = $hash;
return $this; return $this;
@ -50,13 +52,22 @@ final class ArcanistLandCommit
return $this->parents; return $this->parents;
} }
public function addSymbol(ArcanistLandSymbol $symbol) { public function addDirectSymbol(ArcanistLandSymbol $symbol) {
$this->symbols[] = $symbol; $this->directSymbols[] = $symbol;
return $this; return $this;
} }
public function getSymbols() { public function getDirectSymbols() {
return $this->symbols; return $this->directSymbols;
}
public function addIndirectSymbol(ArcanistLandSymbol $symbol) {
$this->indirectSymbols[] = $symbol;
return $this;
}
public function getIndirectSymbols() {
return $this->indirectSymbols;
} }
public function setExplicitRevisionref(ArcanistRevisionRef $ref) { public function setExplicitRevisionref(ArcanistRevisionRef $ref) {

View file

@ -1299,6 +1299,7 @@ final class ArcanistGitLandEngine
} }
$commits = phutil_split_lines($commits, false); $commits = phutil_split_lines($commits, false);
$is_first = false;
foreach ($commits as $line) { foreach ($commits as $line) {
if (!strlen($line)) { if (!strlen($line)) {
continue; continue;
@ -1331,7 +1332,12 @@ final class ArcanistGitLandEngine
} }
$commit = $commit_map[$hash]; $commit = $commit_map[$hash];
$commit->addSymbol($symbol); if ($is_first) {
$commit->addDirectSymbol($symbol);
$is_first = false;
}
$commit->addIndirectSymbol($symbol);
} }
} }

View file

@ -866,7 +866,7 @@ abstract class ArcanistLandEngine extends Phobject {
// TODO: If we have several refs but all but one are abandoned or closed // TODO: If we have several refs but all but one are abandoned or closed
// or authored by someone else, we could guess what you mean. // or authored by someone else, we could guess what you mean.
$symbols = $commit->getSymbols(); $symbols = $commit->getIndirectSymbols();
$raw_symbols = mpull($symbols, 'getSymbol'); $raw_symbols = mpull($symbols, 'getSymbol');
$symbol_list = implode(', ', $raw_symbols); $symbol_list = implode(', ', $raw_symbols);
$display_hash = $this->getDisplayHash($hash); $display_hash = $this->getDisplayHash($hash);
@ -899,11 +899,6 @@ abstract class ArcanistLandEngine extends Phobject {
$display_hash)); $display_hash));
} }
// TODO: Some of the revisions we've identified may be mapped to an
// outdated set of commits. We should look in local branches for a better
// set of commits, and try to confirm that the state we're about to land
// is the current state in Differential.
if ($force_ref) { if ($force_ref) {
$phid_map = array(); $phid_map = array();
foreach ($commit_map as $commit) { foreach ($commit_map as $commit) {
@ -1155,6 +1150,8 @@ abstract class ArcanistLandEngine extends Phobject {
$sets[$revision_phid] = $set; $sets[$revision_phid] = $set;
} }
$sets = $this->filterCommitSets($sets);
if (!$this->getShouldPreview()) { if (!$this->getShouldPreview()) {
$this->confirmImplicitCommits($sets, $symbols); $this->confirmImplicitCommits($sets, $symbols);
} }
@ -1436,4 +1433,62 @@ abstract class ArcanistLandEngine extends Phobject {
return $strategy; return $strategy;
} }
private function filterCommitSets(array $sets) {
assert_instances_of($sets, 'ArcanistLandCommitSet');
$log = $this->getLogEngine();
// If some of the ancestor revisions are already closed, and the user did
// not specifically indicate that we should land them, and we are using
// a "squash" strategy, discard those sets.
if ($this->isSquashStrategy()) {
$discard = array();
foreach ($sets as $key => $set) {
$revision_ref = $set->getRevisionRef();
if (!$revision_ref->isClosed()) {
continue;
}
$symbols = null;
foreach ($set->getCommits() as $commit) {
$commit_symbols = $commit->getDirectSymbols();
if ($commit_symbols) {
$symbols = $commit_symbols;
break;
}
}
if ($symbols) {
continue;
}
$discard[] = $set;
unset($sets[$key]);
}
if ($discard) {
echo tsprintf(
"\n%!\n%W\n",
pht('DISCARDING ANCESTORS'),
pht(
'Some ancestor commits are associated with revisions that have '.
'already been closed. These changes will be skipped:'));
foreach ($discard as $set) {
$this->printCommitSet($set);
}
echo tsprintf("\n");
}
}
// TODO: Some of the revisions we've identified may be mapped to an
// outdated set of commits. We should look in local branches for a better
// set of commits, and try to confirm that the state we're about to land
// is the current state in Differential.
return $sets;
}
} }