Page MenuHomePhabricator

D21686.id51647.diff
No OneTemporary

D21686.id51647.diff

diff --git a/src/repository/api/ArcanistMercurialAPI.php b/src/repository/api/ArcanistMercurialAPI.php
--- a/src/repository/api/ArcanistMercurialAPI.php
+++ b/src/repository/api/ArcanistMercurialAPI.php
@@ -658,7 +658,7 @@
public function doCommit($message) {
$tmp_file = new TempFile();
Filesystem::writeFile($tmp_file, $message);
- $this->execxLocal('commit -l %s', $tmp_file);
+ $this->execxLocal('commit --logfile %s', $tmp_file);
$this->reloadWorkingCopy();
}
@@ -670,19 +670,86 @@
$tmp_file = new TempFile();
Filesystem::writeFile($tmp_file, $message);
- try {
- $this->execxLocal(
- 'commit --amend -l %s',
- $tmp_file);
- } catch (CommandException $ex) {
- if (preg_match('/nothing changed/', $ex->getStdout())) {
- // NOTE: Mercurial considers it an error to make a no-op amend. Although
- // we generally defer to the underlying VCS to dictate behavior, this
- // one seems a little goofy, and we use amend as part of various
- // workflows under the assumption that no-op amends are fine. If this
- // amend failed because it's a no-op, just continue.
+ if ($this->getMercurialFeature('evolve')) {
+ // Evolve makes things a little simpler -- amend and evolve in case it
+ // was a non-head changeset. Evolve shouldn't encounter conflicts since
+ // the amend only changed the commit message.
+ $this->execxLocal('amend --logfile %s --', $tmp_file);
+ // Using evolve when there are no troubled changesets exits and doesn't
+ // indicate an error occurred, so if an error does occur then the repo is
+ // probably in a bad state and we should throw up.
+ $this->execxLocal('evolve --all --');
+ } else {
+ // Handling the amending of a non-head changeset without evolve means
+ // some extra rebasing needs to happen. Rebase the current changeset onto
+ // the same parent but with a new commit message, then rebase each child
+ // branch onto the resulting changeset, and strip the original.
+
+ $hg_analyzer = PhutilBinaryAnalyzer::getForBinary('hg');
+ if ($hg_analyzer->isMercurialTemplatePnodeAvailable()) {
+ $template = '{p1.node} {node}';
+ } else {
+ $template = '{p1node} {node}';
+ }
+
+ list($current_and_parent) = $this->execxLocal(
+ 'log --template %s --rev . --',
+ $template);
+ $nodes = explode(' ', $current_and_parent);
+ $parent = $nodes[0];
+ $current = $nodes[1];
+
+ // For some reason including "{children % '{node}'}" in the above
+ // template unexpectedly ends up printing the current node instead of
+ // child nodes. If it worked this could be a single log invocation.
+ list($children) = $this->execxLocal(
+ 'log --template %s --rev %s',
+ '{node} ',
+ 'children(.)');
+ $child_nodes = array_filter(explode(' ', $children));
+
+ if (empty($child_nodes)) {
+ try {
+ $this->execxLocal('commit --amend --logfile %s --', $tmp_file);
+ } catch (CommandException $ex) {
+ if (preg_match('/nothing changed/', $ex->getStdout())) {
+ // NOTE: Mercurial considers it an error to make a no-op amend.
+ // Although we generally defer to the underlying VCS to dictate
+ // behavior, this one seems a little goofy, and we use amend as
+ // part of various workflows under the assumption that no-op amends
+ // are fine. If this amend failed because it's a no-op, just
+ // continue.
+ } else {
+ throw $ex;
+ }
+ }
} else {
- throw $ex;
+ try {
+ // Mercurial doesn't allow rebasing with a new commit message unless
+ // the `--collapse` flag is also specified... It shouldn't matter
+ // since we're only rebasing a single commit here.
+ $this->execxLocal(
+ 'rebase --dest %s --rev . --keep --collapse --logfile %s --',
+ $parent,
+ $tmp_file);
+
+ list($new_commit) = $this->execxLocal(
+ 'log --rev tip --template %s --',
+ '{node}');
+
+ foreach ($child_nodes as $child) {
+ // "descendants([rev])" will also include [rev] itself
+ $revset = 'descendants('.$child.')';
+ $this->execxLocal(
+ 'rebase --dest %s --rev %s --',
+ $new_commit,
+ $revset);
+ }
+ } catch (CommandException $ex) {
+ $this->execxLocal('rebase --abort');
+ throw $ex;
+ }
+ $this->execxLocal('--config extensions.strip= strip %s', $current);
}
}

File Metadata

Mime Type
text/plain
Expires
Sat, Jan 11, 7:33 AM (16 h, 47 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6984856
Default Alt Text
D21686.id51647.diff (4 KB)

Event Timeline