mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +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:
parent
6fb84e5164
commit
1552397c86
3 changed files with 84 additions and 12 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue