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

Support mutable history in mercurial for arc diff and arc amend

Summary:
This adds basic support for mutable history for arc diff and arc amend for
mercurial. This is purely opt-in (so it shouldn't affect anyone who doesn't want
this feature) by explicitly setting

    "immutable_history" : false

in arc configuration.

This also fixes another instance of weird behaviour for multiple heads - the
first instance was fixed here:
https://github.com/facebook/arcanist/pull/28

Test Plan:
without "immutable_history" turned on)>

When ##arc diff## produces an update diff, it should list only commits that are
ancestors of the current revision - not ones from other heads.

Reviewers: epriestley

CC: csilvers, aran, Koolvin

Differential Revision: https://secure.phabricator.com/D2654
This commit is contained in:
Jamie Wong 2012-06-04 15:30:50 -04:00
parent 6f6fde84cc
commit 1ea5e7e9cf
7 changed files with 104 additions and 16 deletions

View file

@ -459,7 +459,7 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return $this->status;
}
public function amendGitHeadCommit($message) {
public function amendCommit($message) {
$tmp_file = new TempFile();
Filesystem::writeFile($tmp_file, $message);
$this->execxLocal(
@ -681,6 +681,14 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return rtrim($stdout, "\n");
}
public function isHistoryDefaultImmutable() {
return false;
}
public function supportsAmend() {
return true;
}
public function supportsRelativeLocalCommits() {
return true;
}

View file

@ -406,6 +406,19 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
return $this->workingCopyRevision;
}
public function isHistoryDefaultImmutable() {
return true;
}
public function supportsAmend() {
list ($err, $stdout) = $this->execManualLocal('help commit');
if ($err) {
return false;
} else {
return (strstr($stdout, "amend") !== false);
}
}
public function supportsRelativeLocalCommits() {
return true;
}
@ -473,9 +486,9 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
public function getCommitMessageLog() {
list($stdout) = $this->execxLocal(
"log --template '{node}\\1{desc}\\0' --rev %s..%s --",
"log --template '{node}\\1{desc}\\0' --prune %s --rev %s --",
$this->getRelativeCommit(),
$this->getWorkingCopyRevision());
"ancestors({$this->getWorkingCopyRevision()})");
$map = array();
@ -492,6 +505,37 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
ConduitClient $conduit,
array $query) {
$messages = $this->getCommitMessageLog();
$parser = new ArcanistDiffParser();
// First, try to find revisions by explicit revision IDs in commit messages.
$reason_map = array();
$revision_ids = array();
foreach ($messages as $node_id => $message) {
$object = ArcanistDifferentialCommitMessage::newFromRawCorpus($message);
if ($object->getRevisionID()) {
$revision_ids[] = $object->getRevisionID();
$reason_map[$object->getRevisionID()] = $node_id;
}
}
if ($revision_ids) {
$results = $conduit->callMethodSynchronous(
'differential.query',
$query + array(
'ids' => $revision_ids,
));
foreach ($results as $key => $result) {
$hash = substr($reason_map[$result['id']], 0, 16);
$results[$key]['why'] =
"Commit message for '{$hash}' has explicit 'Differential Revision'.";
}
return $results;
}
// Try to find revisions by hash.
$hashes = array();
foreach ($this->getLocalCommitInformation() as $commit) {
@ -517,6 +561,14 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
$this->execxLocal('up');
}
public function amendCommit($message) {
$tmp_file = new TempFile();
Filesystem::writeFile($tmp_file, $message);
$this->execxLocal(
'commit --amend -l %s',
$tmp_file);
}
public function setIncludeDirectoryStateInDiffs($include) {
$this->includeDirectoryStateInDiffs = $include;
return $this;

View file

@ -170,6 +170,8 @@ abstract class ArcanistRepositoryAPI {
abstract public function getLocalCommitInformation();
abstract public function getSourceControlBaseRevision();
abstract public function getCanonicalRevisionName($string);
abstract public function isHistoryDefaultImmutable();
abstract public function supportsAmend();
abstract public function supportsRelativeLocalCommits();
abstract public function getWorkingCopyRevision();
abstract public function updateWorkingCopy();
@ -177,6 +179,10 @@ abstract class ArcanistRepositoryAPI {
ConduitClient $conduit,
array $query);
public function amendCommit() {
throw new ArcanistCapabilityNotSupportedException($this);
}
public function getAllBranches() {
// TODO: Implement for Mercurial/SVN and make abstract.
return array();

View file

@ -507,6 +507,14 @@ EODIFF;
return null;
}
public function isHistoryDefaultImmutable() {
return true;
}
public function supportsAmend() {
return false;
}
public function supportsRelativeLocalCommits() {
return false;
}

View file

@ -32,9 +32,11 @@ EOTEXT
public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT
Supports: git
Supports: git, hg
Amend the working copy after a revision has been accepted, so commits
can be marked 'committed' and pushed upstream.
Supported in Mercurial 2.2 and newer.
EOTEXT
);
}
@ -74,12 +76,13 @@ EOTEXT
$is_show = $this->getArgument('show');
$repository_api = $this->getRepositoryAPI();
if (!($repository_api instanceof ArcanistGitAPI)) {
throw new ArcanistUsageException(
"You may only run 'arc amend' in a git working copy.");
}
if (!$is_show) {
if (!$repository_api->supportsAmend()) {
throw new ArcanistUsageException(
"You may only run 'arc amend' in a git or hg (version ".
"2.2 or newer) working copy.");
}
if ($this->isHistoryImmutable()) {
throw new ArcanistUsageException(
"This project is marked as adhering to a conservative history ".
@ -175,7 +178,8 @@ EOTEXT
echo phutil_console_format(
"Amending commit message to reflect revision **%s**.\n",
"D{$revision_id}: {$revision_title}");
$repository_api->amendGitHeadCommit($message);
$repository_api->amendCommit($message);
$mark_workflow = $this->buildChildWorkflow(
'close-revision',
@ -191,7 +195,7 @@ EOTEXT
protected function getSupportedRevisionControlSystems() {
return array('git');
return array('git', 'hg');
}
}

View file

@ -1027,8 +1027,15 @@ abstract class ArcanistBaseWorkflow {
}
protected function isHistoryImmutable() {
$repository_api = $this->getRepositoryAPI();
$working_copy = $this->getWorkingCopy();
return ($working_copy->getConfig('immutable_history') === true);
$project_config = $working_copy->getConfig('immutable_history');
if ($project_config !== null) {
return $project_config;
}
return $repository_api->isHistoryDefaultImmutable();
}
/**

View file

@ -473,12 +473,15 @@ EOTEXT
'revision_id' => $result['revisionid'],
));
if (!$this->isRawDiffSource()) {
if (!$this->isRawDiffSource() && $this->shouldAmend()) {
$repository_api = $this->getRepositoryAPI();
if (($repository_api instanceof ArcanistGitAPI) &&
$this->shouldAmend()) {
if ($repository_api->supportsAmend()) {
echo "Updating commit message...\n";
$repository_api->amendGitHeadCommit($revised_message);
$repository_api->amendCommit($revised_message);
} else {
echo "Commit message was not amended. Amending commit message is ".
"only supported in git and hg (version 2.2 or newer)";
}
}