1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-09-20 00:49:11 +02:00

(stable) Promote 2019 Week 44

This commit is contained in:
epriestley 2019-11-03 18:06:58 -08:00
commit db1959900a
4 changed files with 459 additions and 202 deletions

View file

@ -8,6 +8,55 @@ final class ArcanistGitLandEngine
private $sourceCommit; private $sourceCommit;
private $mergedRef; private $mergedRef;
private $restoreWhenDestroyed; private $restoreWhenDestroyed;
private $isGitPerforce;
private function setIsGitPerforce($is_git_perforce) {
$this->isGitPerforce = $is_git_perforce;
return $this;
}
private function getIsGitPerforce() {
return $this->isGitPerforce;
}
public function parseArguments() {
$api = $this->getRepositoryAPI();
$onto = $this->getEngineOnto();
$this->setTargetOnto($onto);
$remote = $this->getEngineRemote();
$is_pushable = $api->isPushableRemote($remote);
$is_perforce = $api->isPerforceRemote($remote);
if (!$is_pushable && !$is_perforce) {
throw new PhutilArgumentUsageException(
pht(
'No pushable remote "%s" exists. Use the "--remote" flag to choose '.
'a valid, pushable remote to land changes onto.',
$remote));
}
if ($is_perforce) {
$this->setIsGitPerforce(true);
$this->writeWarn(
pht('P4 MODE'),
pht(
'Operating in Git/Perforce mode after selecting a Perforce '.
'remote.'));
if (!$this->getShouldSquash()) {
throw new PhutilArgumentUsageException(
pht(
'Perforce mode does not support the "merge" land strategy. '.
'Use the "squash" land strategy when landing to a Perforce '.
'remote (you can use "--squash" to select this strategy).'));
}
}
$this->setTargetRemote($remote);
}
public function execute() { public function execute() {
$this->verifySourceAndTargetExist(); $this->verifySourceAndTargetExist();
@ -98,9 +147,34 @@ final class ArcanistGitLandEngine
$this->getTargetFullRef()); $this->getTargetFullRef());
if ($err) { if ($err) {
throw new Exception( $this->writeWarn(
pht('TARGET'),
pht( pht(
'Branch "%s" does not exist in remote "%s".', 'No local ref exists for branch "%s" in remote "%s", attempting '.
'fetch...',
$this->getTargetOnto(),
$this->getTargetRemote()));
$api->execManualLocal(
'fetch %s %s --',
$this->getTargetRemote(),
$this->getTargetOnto());
list($err) = $api->execManualLocal(
'rev-parse --verify %s',
$this->getTargetFullRef());
if ($err) {
throw new Exception(
pht(
'Branch "%s" does not exist in remote "%s".',
$this->getTargetOnto(),
$this->getTargetRemote()));
}
$this->writeInfo(
pht('FETCHED'),
pht(
'Fetched branch "%s" from remote "%s".',
$this->getTargetOnto(), $this->getTargetOnto(),
$this->getTargetRemote())); $this->getTargetRemote()));
} }
@ -124,25 +198,45 @@ final class ArcanistGitLandEngine
$ref = $this->getTargetFullRef(); $ref = $this->getTargetFullRef();
$this->writeInfo(
pht('FETCH'),
pht('Fetching %s...', $ref));
// NOTE: Although this output isn't hugely useful, we need to passthru // NOTE: Although this output isn't hugely useful, we need to passthru
// instead of using a subprocess here because `git fetch` may prompt the // instead of using a subprocess here because `git fetch` may prompt the
// user to enter a password if they're fetching over HTTP with basic // user to enter a password if they're fetching over HTTP with basic
// authentication. See T10314. // authentication. See T10314.
$err = $api->execPassthru( if ($this->getIsGitPerforce()) {
'fetch --quiet -- %s %s', $this->writeInfo(
$this->getTargetRemote(), pht('P4 SYNC'),
$this->getTargetOnto()); pht('Synchronizing "%s" from Perforce...', $ref));
if ($err) { $sync_ref = sprintf(
throw new ArcanistUsageException( 'refs/remotes/%s/%s',
pht( $this->getTargetRemote(),
'Fetch failed! Fix the error and run "%s" again.', $this->getTargetOnto());
'arc land'));
$err = $api->execPassthru(
'p4 sync --silent --branch %R --',
$sync_ref);
if ($err) {
throw new ArcanistUsageException(
pht(
'Perforce sync failed! Fix the error and run "arc land" again.'));
}
} else {
$this->writeInfo(
pht('FETCH'),
pht('Fetching "%s"...', $ref));
$err = $api->execPassthru(
'fetch --quiet -- %s %s',
$this->getTargetRemote(),
$this->getTargetOnto());
if ($err) {
throw new ArcanistUsageException(
pht(
'Fetch failed! Fix the error and run "arc land" again.'));
}
} }
} }
@ -212,21 +306,68 @@ final class ArcanistGitLandEngine
private function pushChange() { private function pushChange() {
$api = $this->getRepositoryAPI(); $api = $this->getRepositoryAPI();
$this->writeInfo( if ($this->getIsGitPerforce()) {
pht('PUSHING'), $this->writeInfo(
pht('Pushing changes to "%s".', $this->getTargetFullRef())); pht('SUBMITTING'),
pht('Submitting changes to "%s".', $this->getTargetFullRef()));
$err = $api->execPassthru( $config_argv = array();
'push -- %s %s:%s',
$this->getTargetRemote(),
$this->mergedRef,
$this->getTargetOnto());
if ($err) { // Skip the "git p4 submit" interactive editor workflow. We expect
throw new ArcanistUsageException( // the commit message that "arc land" has built to be satisfactory.
pht( $config_argv[] = '-c';
'Push failed! Fix the error and run "%s" again.', $config_argv[] = 'git-p4.skipSubmitEdit=true';
'arc land'));
// Skip the "git p4 submit" confirmation prompt if the user does not edit
// the submit message.
$config_argv[] = '-c';
$config_argv[] = 'git-p4.skipSubmitEditCheck=true';
$flags_argv = array();
// Disable implicit "git p4 rebase" as part of submit. We're allowing
// the implicit "git p4 sync" to go through since this puts us in a
// state which is generally similar to the state after "git push", with
// updated remotes.
// We could do a manual "git p4 sync" with a more narrow "--branch"
// instead, but it's not clear that this is beneficial.
$flags_argv[] = '--disable-rebase';
// Detect moves and submit them to Perforce as move operations.
$flags_argv[] = '-M';
// If we run into a conflict, abort the operation. We expect users to
// fix conflicts and run "arc land" again.
$flags_argv[] = '--conflict=quit';
$err = $api->execPassthru(
'%LR p4 submit %LR --commit %R --',
$config_argv,
$flags_argv,
$this->mergedRef);
if ($err) {
throw new ArcanistUsageException(
pht(
'Submit failed! Fix the error and run "arc land" again.'));
}
} else {
$this->writeInfo(
pht('PUSHING'),
pht('Pushing changes to "%s".', $this->getTargetFullRef()));
$err = $api->execPassthru(
'push -- %s %s:%s',
$this->getTargetRemote(),
$this->mergedRef,
$this->getTargetOnto());
if ($err) {
throw new ArcanistUsageException(
pht(
'Push failed! Fix the error and run "arc land" again.'));
}
} }
} }
@ -332,40 +473,54 @@ final class ArcanistGitLandEngine
return; return;
} }
if (!$path->isConnectedToRemote()) { $is_perforce = $this->getIsGitPerforce();
$this->writeInfo(
pht('UPDATE'), if ($is_perforce) {
pht( // If we're in Perforce mode, we don't expect to have a meaningful
'Local branch "%s" is not connected to a remote, staying on '. // path to the remote: the "p4" remote is not a real remote, and
'detached HEAD.', // "git p4" commands do not configure branch upstreams to provide
$local_branch)); // a path.
return;
// Just pretend the target branch is connected directly to the remote,
// since this is effectively the behavior of Perforce and appears to
// do the right thing.
$cascade_branches = array($local_branch);
} else {
if (!$path->isConnectedToRemote()) {
$this->writeInfo(
pht('UPDATE'),
pht(
'Local branch "%s" is not connected to a remote, staying on '.
'detached HEAD.',
$local_branch));
return;
}
$remote_remote = $path->getRemoteRemoteName();
$remote_branch = $path->getRemoteBranchName();
$remote_actual = $remote_remote.'/'.$remote_branch;
$remote_expect = $this->getTargetFullRef();
if ($remote_actual != $remote_expect) {
$this->writeInfo(
pht('UPDATE'),
pht(
'Local branch "%s" is connected to a remote ("%s") other than '.
'the target remote ("%s"), staying on detached HEAD.',
$local_branch,
$remote_actual,
$remote_expect));
return;
}
// If we get this far, we have a sequence of branches which ultimately
// connect to the remote. We're going to try to update them all in reverse
// order, from most-upstream to most-local.
$cascade_branches = $path->getLocalBranches();
$cascade_branches = array_reverse($cascade_branches);
} }
$remote_remote = $path->getRemoteRemoteName();
$remote_branch = $path->getRemoteBranchName();
$remote_actual = $remote_remote.'/'.$remote_branch;
$remote_expect = $this->getTargetFullRef();
if ($remote_actual != $remote_expect) {
$this->writeInfo(
pht('UPDATE'),
pht(
'Local branch "%s" is connected to a remote ("%s") other than '.
'the target remote ("%s"), staying on detached HEAD.',
$local_branch,
$remote_actual,
$remote_expect));
return;
}
// If we get this far, we have a sequence of branches which ultimately
// connect to the remote. We're going to try to update them all in reverse
// order, from most-upstream to most-local.
$cascade_branches = $path->getLocalBranches();
$cascade_branches = array_reverse($cascade_branches);
// First, check if any of them are ahead of the remote. // First, check if any of them are ahead of the remote.
$ahead_of_remote = array(); $ahead_of_remote = array();
@ -428,7 +583,12 @@ final class ArcanistGitLandEngine
} }
} }
if ($cascade_targets) { if ($is_perforce) {
// In Perforce, we've already set the remote to the right state with an
// implicit "git p4 sync" during "git p4 submit", and "git pull" isn't a
// meaningful operation. We're going to skip this step and jump down to
// the "git reset --hard" below to get everything into the right state.
} else if ($cascade_targets) {
$this->writeInfo( $this->writeInfo(
pht('UPDATE'), pht('UPDATE'),
pht( pht(
@ -445,7 +605,10 @@ final class ArcanistGitLandEngine
$cascade_branch)); $cascade_branch));
$api->execxLocal('checkout %s --', $cascade_branch); $api->execxLocal('checkout %s --', $cascade_branch);
$api->execxLocal('pull --'); $api->execxLocal(
'pull %s %s --',
$this->getTargetRemote(),
$cascade_branch);
} }
if (!$local_ahead) { if (!$local_ahead) {
@ -569,16 +732,27 @@ final class ArcanistGitLandEngine
} }
private function didHoldChanges() { private function didHoldChanges() {
$this->writeInfo( if ($this->getIsGitPerforce()) {
pht('HOLD'), $this->writeInfo(
pht( pht('HOLD'),
'Holding change locally, it has not been pushed.')); pht(
'Holding change locally, it has not been submitted.'));
$push_command = csprintf( $push_command = csprintf(
'$ git push -- %R %R:%R', '$ git p4 submit -M --commit %R --',
$this->getTargetRemote(), $this->mergedRef);
$this->mergedRef, } else {
$this->getTargetOnto()); $this->writeInfo(
pht('HOLD'),
pht(
'Holding change locally, it has not been pushed.'));
$push_command = csprintf(
'$ git push -- %R %R:%R',
$this->getTargetRemote(),
$this->mergedRef,
$this->getTargetOnto());
}
$restore_command = csprintf( $restore_command = csprintf(
'$ git checkout %R --', '$ git checkout %R --',
@ -587,9 +761,9 @@ final class ArcanistGitLandEngine
echo tsprintf( echo tsprintf(
"\n%s\n\n". "\n%s\n\n".
"%s\n\n". "%s\n\n".
" %s\n\n". " **%s**\n\n".
"%s\n\n". "%s\n\n".
" %s\n\n". " **%s**\n\n".
"%s\n", "%s\n",
pht( pht(
'This local working copy now contains the merged changes in a '. 'This local working copy now contains the merged changes in a '.
@ -597,7 +771,7 @@ final class ArcanistGitLandEngine
pht('You can push the changes manually with this command:'), pht('You can push the changes manually with this command:'),
$push_command, $push_command,
pht( pht(
'You can go back to how things were before you ran `arc land` with '. 'You can go back to how things were before you ran "arc land" with '.
'this command:'), 'this command:'),
$restore_command, $restore_command,
pht( pht(
@ -615,4 +789,125 @@ final class ArcanistGitLandEngine
return !$err; return !$err;
} }
private function getEngineOnto() {
$source_ref = $this->getSourceRef();
$onto = $this->getOntoArgument();
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected with the "--onto" flag.',
$onto));
return $onto;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($source_ref);
if ($path->getLength()) {
$cycle = $path->getCycle();
if ($cycle) {
$this->writeWarn(
pht('LOCAL CYCLE'),
pht(
'Local branch tracks an upstream, but following it leads to a '.
'local cycle; ignoring branch upstream.'));
echo tsprintf(
"\n %s\n\n",
implode(' -> ', $cycle));
} else {
if ($path->isConnectedToRemote()) {
$onto = $path->getRemoteBranchName();
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$onto));
return $onto;
} else {
$this->writeInfo(
pht('NO PATH TO UPSTREAM'),
pht(
'Local branch tracks an upstream, but there is no path '.
'to a remote; ignoring branch upstream.'));
}
}
}
$workflow = $this->getWorkflow();
$config_key = 'arc.land.onto.default';
$onto = $workflow->getConfigFromAnySource($config_key);
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by "%s" configuration.',
$onto,
$config_key));
return $onto;
}
$onto = 'master';
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", the default target under git.',
$onto));
return $onto;
}
private function getEngineRemote() {
$source_ref = $this->getSourceRef();
$remote = $this->getRemoteArgument();
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected with the "--remote" flag.',
$remote));
return $remote;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($source_ref);
$remote = $path->getRemoteRemoteName();
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$remote));
return $remote;
}
$remote = 'p4';
if ($api->isPerforceRemote($remote)) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using Perforce remote "%s". The existence of this remote implies '.
'this working copy was synchronized from a Perforce repository.',
$remote));
return $remote;
}
$remote = 'origin';
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", the default remote under Git.',
$remote));
return $remote;
}
} }

View file

@ -13,6 +13,8 @@ abstract class ArcanistLandEngine extends Phobject {
private $shouldSquash; private $shouldSquash;
private $shouldDeleteRemote; private $shouldDeleteRemote;
private $shouldPreview; private $shouldPreview;
private $remoteArgument;
private $ontoArgument;
// TODO: This is really grotesque. // TODO: This is really grotesque.
private $buildMessageCallback; private $buildMessageCallback;
@ -117,6 +119,25 @@ abstract class ArcanistLandEngine extends Phobject {
return $this->commitMessageFile; return $this->commitMessageFile;
} }
final public function setRemoteArgument($remote_argument) {
$this->remoteArgument = $remote_argument;
return $this;
}
final public function getRemoteArgument() {
return $this->remoteArgument;
}
final public function setOntoArgument($onto_argument) {
$this->ontoArgument = $onto_argument;
return $this;
}
final public function getOntoArgument() {
return $this->ontoArgument;
}
abstract public function parseArguments();
abstract public function execute(); abstract public function execute();
abstract protected function getLandingCommits(); abstract protected function getLandingCommits();

View file

@ -464,15 +464,27 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
*/ */
public function getFullGitDiff($base, $head = null) { public function getFullGitDiff($base, $head = null) {
$options = $this->getDiffFullOptions(); $options = $this->getDiffFullOptions();
$config_options = array();
// See T13432. Disable the rare "diff.suppressBlankEmpty" configuration
// option, which discards the " " (space) change type prefix on unchanged
// blank lines. At time of writing the parser does not handle these
// properly, but generating a more-standard diff is generally desirable
// even if a future parser handles this case more gracefully.
$config_options[] = '-c';
$config_options[] = 'diff.suppressBlankEmpty=false';
if ($head !== null) { if ($head !== null) {
list($stdout) = $this->execxLocal( list($stdout) = $this->execxLocal(
"diff {$options} %s %s --", "%LR diff {$options} %s %s --",
$config_options,
$base, $base,
$head); $head);
} else { } else {
list($stdout) = $this->execxLocal( list($stdout) = $this->execxLocal(
"diff {$options} %s --", "%LR diff {$options} %s --",
$config_options,
$base); $base);
} }
@ -1550,4 +1562,31 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI {
return $path; return $path;
} }
public function isPerforceRemote($remote_name) {
// See T13434. In Perforce workflows, "git p4 clone" creates "p4" refs
// under "refs/remotes/", but does not define a real remote named "p4".
// We treat this remote as though it were a real remote during "arc land",
// but it does not respond to commands like "git remote show p4", so we
// need to handle it specially.
if ($remote_name !== 'p4') {
return false;
}
$remote_dir = $this->getMetadataPath().'/refs/remotes/p4';
if (!Filesystem::pathExists($remote_dir)) {
return false;
}
return true;
}
public function isPushableRemote($remote_name) {
list($err, $stdout) = $this->execManualLocal(
'remote get-url --push -- %s',
$remote_name);
return !$err;
}
} }

View file

@ -44,10 +44,10 @@ EOTEXT
public function getCommandHelp() { public function getCommandHelp() {
return phutil_console_format(<<<EOTEXT return phutil_console_format(<<<EOTEXT
Supports: git, hg Supports: git, git/p4, hg
Publish an accepted revision after review. This command is the last Publish an accepted revision after review. This command is the last
step in the standard Differential pre-publish code review workflow. step in the standard Differential code review workflow.
This command merges and pushes changes associated with an accepted This command merges and pushes changes associated with an accepted
revision that are currently sitting in __ref__, which is usually the revision that are currently sitting in __ref__, which is usually the
@ -57,6 +57,9 @@ EOTEXT
Under Git: branches, tags, and arbitrary commits (detached HEADs) Under Git: branches, tags, and arbitrary commits (detached HEADs)
may be landed. may be landed.
Under Git/Perforce: branches, tags, and arbitrary commits may
be submitted.
Under Mercurial: branches and bookmarks may be landed, but only Under Mercurial: branches and bookmarks may be landed, but only
onto a target of the same type. See T3855. onto a target of the same type. See T3855.
@ -66,7 +69,8 @@ EOTEXT
A target branch is selected by examining these sources in order: A target branch is selected by examining these sources in order:
- the **--onto** flag; - the **--onto** flag;
- the upstream of the current branch, recursively (Git only); - the upstream of the branch targeted by the land operation,
recursively (Git only);
- the __arc.land.onto.default__ configuration setting; - the __arc.land.onto.default__ configuration setting;
- or by falling back to a standard default: - or by falling back to a standard default:
- "master" in Git; - "master" in Git;
@ -76,6 +80,8 @@ EOTEXT
- the **--remote** flag; - the **--remote** flag;
- the upstream of the current branch, recursively (Git only); - the upstream of the current branch, recursively (Git only);
- the special "p4" remote which indicates a repository has
been synchronized with Perforce (Git only);
- or by falling back to a standard default: - or by falling back to a standard default:
- "origin" in Git; - "origin" in Git;
- the default remote in Mercurial. - the default remote in Mercurial.
@ -159,7 +165,7 @@ EOTEXT
'remote' => array( 'remote' => array(
'param' => 'origin', 'param' => 'origin',
'help' => pht( 'help' => pht(
"Push to a remote other than the default ('origin' in git)."), 'Push to a remote other than the default.'),
), ),
'merge' => array( 'merge' => array(
'help' => pht( 'help' => pht(
@ -224,23 +230,36 @@ EOTEXT
} }
if ($engine) { if ($engine) {
$this->readEngineArguments();
$this->requireCleanWorkingCopy();
$should_hold = $this->getArgument('hold'); $should_hold = $this->getArgument('hold');
$remote_arg = $this->getArgument('remote');
$onto_arg = $this->getArgument('onto');
$engine $engine
->setWorkflow($this) ->setWorkflow($this)
->setRepositoryAPI($this->getRepositoryAPI()) ->setRepositoryAPI($this->getRepositoryAPI())
->setSourceRef($this->branch) ->setSourceRef($this->branch)
->setTargetRemote($this->remote)
->setTargetOnto($this->onto)
->setShouldHold($should_hold) ->setShouldHold($should_hold)
->setShouldKeep($this->keepBranch) ->setShouldKeep($this->keepBranch)
->setShouldSquash($this->useSquash) ->setShouldSquash($this->useSquash)
->setShouldPreview($this->preview) ->setShouldPreview($this->preview)
->setRemoteArgument($remote_arg)
->setOntoArgument($onto_arg)
->setBuildMessageCallback(array($this, 'buildEngineMessage')); ->setBuildMessageCallback(array($this, 'buildEngineMessage'));
// The goal here is to raise errors with flags early (which is cheap),
// before we test if the working copy is clean (which can be slow). This
// could probably be structured more cleanly.
$engine->parseArguments();
// This must be configured or we fail later inside "buildEngineMessage()".
// This is less than ideal.
$this->ontoRemoteBranch = sprintf(
'%s/%s',
$engine->getTargetRemote(),
$engine->getTargetOnto());
$this->requireCleanWorkingCopy();
$engine->execute(); $engine->execute();
if (!$should_hold && !$this->preview) { if (!$should_hold && !$this->preview) {
@ -337,123 +356,6 @@ EOTEXT
return $refspec; return $refspec;
} }
private function readEngineArguments() {
// NOTE: This is hard-coded for Git right now.
// TODO: Clean this up and move it into LandEngines.
$onto = $this->getEngineOnto();
$remote = $this->getEngineRemote();
// This just overwrites work we did earlier, but it has to be up in this
// class for now because other parts of the workflow still depend on it.
$this->onto = $onto;
$this->remote = $remote;
$this->ontoRemoteBranch = $this->remote.'/'.$onto;
}
private function getEngineOnto() {
$onto = $this->getArgument('onto');
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by the --onto flag.',
$onto));
return $onto;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($this->branch);
if ($path->getLength()) {
$cycle = $path->getCycle();
if ($cycle) {
$this->writeWarn(
pht('LOCAL CYCLE'),
pht(
'Local branch tracks an upstream, but following it leads to a '.
'local cycle; ignoring branch upstream.'));
echo tsprintf(
"\n %s\n\n",
implode(' -> ', $cycle));
} else {
if ($path->isConnectedToRemote()) {
$onto = $path->getRemoteBranchName();
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$onto));
return $onto;
} else {
$this->writeInfo(
pht('NO PATH TO UPSTREAM'),
pht(
'Local branch tracks an upstream, but there is no path '.
'to a remote; ignoring branch upstream.'));
}
}
}
$config_key = 'arc.land.onto.default';
$onto = $this->getConfigFromAnySource($config_key);
if ($onto !== null) {
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", selected by "%s" configuration.',
$onto,
$config_key));
return $onto;
}
$onto = 'master';
$this->writeInfo(
pht('TARGET'),
pht(
'Landing onto "%s", the default target under git.',
$onto));
return $onto;
}
private function getEngineRemote() {
$remote = $this->getArgument('remote');
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected by the --remote flag.',
$remote));
return $remote;
}
$api = $this->getRepositoryAPI();
$path = $api->getPathToUpstream($this->branch);
$remote = $path->getRemoteRemoteName();
if ($remote !== null) {
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", selected by following tracking branches '.
'upstream to the closest remote.',
$remote));
return $remote;
}
$remote = 'origin';
$this->writeInfo(
pht('REMOTE'),
pht(
'Using remote "%s", the default remote under git.',
$remote));
return $remote;
}
private function readArguments() { private function readArguments() {
$repository_api = $this->getRepositoryAPI(); $repository_api = $this->getRepositoryAPI();
$this->isGit = $repository_api instanceof ArcanistGitAPI; $this->isGit = $repository_api instanceof ArcanistGitAPI;