1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-11 07:11:03 +01:00

Approximate "git merge-base" in Mercurial

Summary: Find the relative commit by finding the first non-outgoing commit, so
we don't show changes caused by merges we've performed since the last time we
pushed.

Test Plan: Checked out two hg working copies, A and B. Made a change in A. Made
a change in B. Pushed B. Merged in A. Made another change in A. Ran "arc diff"
in A. Got only changes I made in A in the diff, not the change from B.

Reviewers: Makinde, btrahan, jungejason

Reviewed By: btrahan

CC: aran, btrahan

Differential Revision: https://secure.phabricator.com/D1339
This commit is contained in:
epriestley 2012-01-06 13:14:41 -08:00
parent c49e9863d4
commit 9249ede952

View file

@ -1,7 +1,7 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -69,33 +69,51 @@ class ArcanistMercurialAPI extends ArcanistRepositoryAPI {
public function getRelativeCommit() {
if (empty($this->relativeCommit)) {
list($stdout) = execx(
'(cd %s && hg outgoing --branch `hg branch` --limit 1 --style default)',
'(cd %s && hg outgoing --branch `hg branch` --style default)',
$this->getPath());
$logs = ArcanistMercurialParser::parseMercurialLog($stdout);
if (!count($logs)) {
throw new ArcanistUsageException("You have no outgoing changes!");
}
$oldest_log = head($logs);
$oldest_rev = $oldest_log['rev'];
// NOTE: The "^" and "~" syntaxes were only added in hg 1.9, which is new
// as of July 2011, so do this in a compatible way. Also, "hg log" and
// "hg outgoing" don't necessarily show parents (even if given an explicit
// template consisting of just the parents token) so we need to separately
// execute "hg parents".
$outgoing_revs = ipull($logs, 'rev');
list($stdout) = execx(
'(cd %s && hg parents --style default --rev %s)',
$this->getPath(),
$oldest_rev);
$parents_logs = ArcanistMercurialParser::parseMercurialLog($stdout);
$first_parent = head($parents_logs);
if (!$first_parent) {
throw new ArcanistUsageException(
"Oldest outgoing change has no parent revision!");
// This is essentially an implementation of a theoretical `hg merge-base`
// command.
$against = 'tip';
while (true) {
// NOTE: The "^" and "~" syntaxes were only added in hg 1.9, which is
// new as of July 2011, so do this in a compatible way. Also, "hg log"
// and "hg outgoing" don't necessarily show parents (even if given an
// explicit template consisting of just the parents token) so we need
// to separately execute "hg parents".
list($stdout) = execx(
'(cd %s && hg parents --style default --rev %s)',
$this->getPath(),
$against);
$parents_logs = ArcanistMercurialParser::parseMercurialLog($stdout);
list($p1, $p2) = array_merge($parents_logs, array(null, null));
if ($p1 && !in_array($p1['rev'], $outgoing_revs)) {
$against = $p1['rev'];
break;
} else if ($p2 && !in_array($p2['rev'], $outgoing_revs)) {
$against = $p2['rev'];
break;
} else if ($p1) {
$against = $p1['rev'];
} else {
// This is the case where you have a new repository and the entire
// thing is outgoing; Mercurial literally accepts "--rev null" as
// meaning "diff against the empty state".
$against = 'null';
break;
}
}
$this->relativeCommit = $first_parent['rev'];
$this->relativeCommit = $against;
}
return $this->relativeCommit;
}