Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14621838
D21686.id51647.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
4 KB
Referenced Files
None
Subscribers
None
D21686.id51647.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D21686: Update "arc diff" to amend non-head commits with Mercurial
Attached
Detach File
Event Timeline
Log In to Comment