Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14621845
D21686.id51648.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
5 KB
Referenced Files
None
Subscribers
None
D21686.id51648.diff
View Options
diff --git a/src/land/engine/ArcanistMercurialLandEngine.php b/src/land/engine/ArcanistMercurialLandEngine.php
--- a/src/land/engine/ArcanistMercurialLandEngine.php
+++ b/src/land/engine/ArcanistMercurialLandEngine.php
@@ -803,8 +803,8 @@
// descendants and the min commit has no ancestors. The min/max terms are
// used in a topological sense as chronological terms for commits can be
// misleading or incorrect in certain situations.
- $max_commit = last($commits)->getHash();
$min_commit = head($commits)->getHash();
+ $max_commit = last($commits)->getHash();
$revision_ref = $set->getRevisionRef();
$commit_message = $revision_ref->getCommitMessage();
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,11 +658,14 @@
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();
}
public function amendCommit($message = null) {
+ // TODO: If the message isn't being changed and there are no unsaved
+ // changes then just return without making any modifications?
+
if ($message === null) {
$message = $this->getCommitMessage('.');
}
@@ -670,22 +673,97 @@
$tmp_file = new TempFile();
Filesystem::writeFile($tmp_file, $message);
+ if ($this->getMercurialFeature('evolve')) {
+ $this->execxLocal('amend --logfile %s --', $tmp_file);
+ $this->execxLocal('evolve --all --');
+ $this->reloadWorkingCopy();
+ return;
+ }
+
+ // 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 prints the current node and not 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;
+ }
+ }
+ $this->reloadWorkingCopy();
+ return;
+ }
+
+ // TODO: Stash unsaved changes.
+
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(
- 'commit --amend -l %s',
+ 'rebase --dest %s --rev . --keep --collapse --logfile %s --',
+ $parent,
$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;
+ $this->execxLocal('rebase --abort');
+ throw $ex;
+ }
+
+ list($new_commit) = $this->execxLocal(
+ 'log --rev tip --template %s --',
+ '{node}');
+
+ // TODO: Un-stash unsaved changes, amend to the new commit, get new commit.
+
+ try {
+ foreach ($child_nodes as $child) {
+ // descendants(rev) will also include rev itself which is why this
+ // can't just use a single rebase of descendants($current).
+ $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);
+
$this->reloadWorkingCopy();
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 11, 7:43 AM (16 h, 26 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6984861
Default Alt Text
D21686.id51648.diff (5 KB)
Attached To
Mode
D21686: Update "arc diff" to amend non-head commits with Mercurial
Attached
Detach File
Event Timeline
Log In to Comment