Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14621821
D21686.id51663.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
D21686.id51663.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,37 +658,120 @@
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) {
+ $path_statuses = $this->buildUncommittedStatus();
+
if ($message === null) {
+ if (empty($path_statuses)) {
+ // If there are no changes to the working directory and the message is
+ // not being changed then there's nothing to amend.
+ return;
+ }
+
$message = $this->getCommitMessage('.');
}
$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.
- } else {
+ if ($this->getMercurialFeature('evolve')) {
+ $this->execxLocal('amend --logfile %s --', $tmp_file);
+ try {
+ $this->execxLocal('evolve --all --');
+ } catch (CommandException $ex) {
+ $this->execxLocal('evolve --abort --');
throw $ex;
}
+ $this->reloadWorkingCopy();
+ return;
+ }
+
+ // Get the child nodes of the current changeset.
+ list($children) = $this->execxLocal(
+ 'log --template %s --rev %s --',
+ '{node} ',
+ 'children(.)');
+ $child_nodes = array_filter(explode(' ', $children));
+
+ // For a head commit we can simply use `commit --amend` for both new commit
+ // message and amending changes from the working directory.
+ 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 {
+ $this->amendNonHeadCommit($child_nodes, $tmp_file);
}
$this->reloadWorkingCopy();
}
+ /**
+ * Amends a non-head commit with a new message and file changes. This
+ * strategy is for Mercurial repositories without the evolve extension.
+ *
+ * 1. Run 'arc-amend' which uses Mercurial internals to amend the current
+ * commit with updated message/file-changes. It results in a new commit
+ * from the right parent
+ * 2. For each branch from the original commit, rebase onto the new commit,
+ * removing the original branch. Note that there is potential for this to
+ * cause a conflict but this is something the user has to address.
+ * 3. Strip the original commit.
+ *
+ * @param array The list of child changesets off the original commit.
+ * @param file The file containing the new commit message.
+ */
+ private function amendNonHeadCommit($child_nodes, $tmp_file) {
+ list($current) = $this->execxLocal(
+ 'log --template %s --rev . --',
+ '{node}');
+
+ $argv = array();
+ foreach ($this->getMercurialExtensionArguments() as $arg) {
+ $argv[] = $arg;
+ }
+ $argv[] = 'arc-amend';
+ $argv[] = '--logfile';
+ $argv[] = $tmp_file;
+ $this->execxLocal('%Ls', $argv);
+
+ list($new_commit) = $this->execxLocal(
+ 'log --rev tip --template %s --',
+ '{node}');
+
+ try {
+ foreach ($child_nodes as $child) {
+ // descendants(rev) will also include rev itself which is why this
+ // can't use a single rebase of descendants($current).
+ $revset = hgsprintf('descendants(%s)', $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 --rev %s --',
+ $current);
+ }
+
public function getCommitSummary($commit) {
if ($commit == 'null') {
return pht('(The Empty Void)');
diff --git a/src/repository/state/ArcanistRepositoryLocalState.php b/src/repository/state/ArcanistRepositoryLocalState.php
--- a/src/repository/state/ArcanistRepositoryLocalState.php
+++ b/src/repository/state/ArcanistRepositoryLocalState.php
@@ -192,10 +192,27 @@
return false;
}
+ /**
+ * Stash uncommitted changes temporarily. Use {@method:restoreStash()} to
+ * bring these changes back.
+ *
+ * Note that on Git repositories the stash acts as a stack, so saving the
+ * stash must match appropriately to restoring the stash.
+ *
+ * @return wild On Git this returns true, on Mercurial this returns a name
+ * (string) which references the stash that was made. This name
+ * should later be passed to {@method:restoreStash()}.
+ */
protected function saveStash() {
throw new PhutilMethodNotImplementedException();
}
+ /**
+ * Restores changes that were previously stashed by {@method:saveStash()}.
+ *
+ * @param wild On Git this parameter is unused, on Mercurial this should be
+ * the name (string) returned from {@method:saveStash()}.
+ */
protected function restoreStash($ref) {
throw new PhutilMethodNotImplementedException();
}
diff --git a/support/hg/arc-hg.py b/support/hg/arc-hg.py
--- a/support/hg/arc-hg.py
+++ b/support/hg/arc-hg.py
@@ -28,6 +28,24 @@
cmdtable = {}
command = registrar.command(cmdtable)
+@command(
+ b'arc-amend',
+ [
+ (b'l', b'logfile', b'', _(b'read commit message from file'), _(b'FILE')),
+ (b'm', b'message', None, _(b'use text as commit message'), _(b'TEXT')),
+ ],
+ _(b'[--logfile FILE] [--message TEXT]'))
+def amend(ui, repo, source=None, **opts):
+ # The option keys seem to come in as 'str' type but the cmdutil.amend() code
+ # expects them as binary.
+ if opts.get('logfile'):
+ opts[b'logfile'] = opts.get('logfile')
+ if opts.get('message'):
+ opts[b'message'] = opts.get('message')
+
+ cmdutil.amend(ui, repo, repo[b'.'], {}, [], opts)
+ return 0
+
@command(
b'arc-ls-markers',
[(b'', b'output', b'',
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Jan 11, 7:19 AM (16 h, 34 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6984841
Default Alt Text
D21686.id51663.diff (7 KB)
Attached To
Mode
D21686: Update "arc diff" to amend non-head commits with Mercurial
Attached
Detach File
Event Timeline
Log In to Comment