mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-10 08:52:39 +01:00
Arcanist - stop arc land if local is ahead of remote
Summary: Fixes T4291. Also pht user-facing strings. Test Plan: made a branch `foo` off master. made a commit and a diff in `foo`. switched backed to master and cowboy committed some thing. went back to branch`foo`, did an arc land, and saw the error message. went back to master, did a git resert --hard HEAD^1, went back to branch `foo`, and then successfully arc landed. also ran arc help land and things looked good Reviewers: epriestley Reviewed By: epriestley Subscribers: epriestley, Korvin Maniphest Tasks: T4291 Differential Revision: https://secure.phabricator.com/D8738
This commit is contained in:
parent
ac528ab3a8
commit
02456c0aed
1 changed files with 204 additions and 153 deletions
|
@ -81,70 +81,76 @@ EOTEXT
|
||||||
return array(
|
return array(
|
||||||
'onto' => array(
|
'onto' => array(
|
||||||
'param' => 'master',
|
'param' => 'master',
|
||||||
'help' => "Land feature branch onto a branch other than the default ".
|
'help' => pht('Land feature branch onto a branch other than the '.
|
||||||
"('master' in git, 'default' in hg). You can change the ".
|
'default (\'master\' in git, \'default\' in hg). You '.
|
||||||
"default by setting 'arc.land.onto.default' with ".
|
'can change the default by setting '.
|
||||||
"`arc set-config` or for the entire project in .arcconfig.",
|
'\'arc.land.onto.default\' with `arc set-config` or '.
|
||||||
|
'for the entire project in .arcconfig.'),
|
||||||
),
|
),
|
||||||
'hold' => array(
|
'hold' => array(
|
||||||
'help' => "Prepare the change to be pushed, but do not actually ".
|
'help' => pht('Prepare the change to be pushed, but do not actually '.
|
||||||
"push it.",
|
'push it.'),
|
||||||
),
|
),
|
||||||
'keep-branch' => array(
|
'keep-branch' => array(
|
||||||
'help' => "Keep the feature branch after pushing changes to the ".
|
'help' => pht('Keep the feature branch after pushing changes to the '.
|
||||||
"remote (by default, it is deleted).",
|
'remote (by default, it is deleted).'),
|
||||||
),
|
),
|
||||||
'remote' => array(
|
'remote' => array(
|
||||||
'param' => 'origin',
|
'param' => 'origin',
|
||||||
'help' => "Push to a remote other than the default ('origin' in git).",
|
'help' => pht('Push to a remote other than the default (\'origin\' '.
|
||||||
|
'in git).'),
|
||||||
),
|
),
|
||||||
'merge' => array(
|
'merge' => array(
|
||||||
'help' => 'Perform a --no-ff merge, not a --squash merge. If the '.
|
'help' => pht('Perform a --no-ff merge, not a --squash merge. If the '.
|
||||||
'project is marked as having an immutable history, this is '.
|
'project is marked as having an immutable history, '.
|
||||||
'the default behavior.',
|
'this is the default behavior.'),
|
||||||
'supports' => array(
|
'supports' => array(
|
||||||
'git',
|
'git',
|
||||||
),
|
),
|
||||||
'nosupport' => array(
|
'nosupport' => array(
|
||||||
'hg' => 'Use the --squash strategy when landing in mercurial.',
|
'hg' => pht('Use the --squash strategy when landing in mercurial.'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'squash' => array(
|
'squash' => array(
|
||||||
'help' => 'Perform a --squash merge, not a --no-ff merge. If the '.
|
'help' => pht('Perform a --squash merge, not a --no-ff merge. If the '.
|
||||||
'project is marked as having a mutable history, this is '.
|
'project is marked as having a mutable history, this '.
|
||||||
'the default behavior.',
|
'is the default behavior.'),
|
||||||
'conflicts' => array(
|
'conflicts' => array(
|
||||||
'merge' => '--merge and --squash are conflicting merge strategies.',
|
'merge' => '--merge and --squash are conflicting merge strategies.',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'delete-remote' => array(
|
'delete-remote' => array(
|
||||||
'help' => 'Delete the feature branch in the remote after '.
|
'help' => pht('Delete the feature branch in the remote after '.
|
||||||
'landing it.',
|
'landing it.'),
|
||||||
'conflicts' => array(
|
'conflicts' => array(
|
||||||
'keep-branch' => true,
|
'keep-branch' => true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'update-with-rebase' => array(
|
'update-with-rebase' => array(
|
||||||
'help' => 'When updating the feature branch, use rebase instead of '.
|
'help' => pht('When updating the feature branch, use rebase '.
|
||||||
'merge. This might make things work better in some cases.'.
|
'instead of merge. This might make things work '.
|
||||||
' Set arc.land.update.default to \'rebase\' to make this '.
|
'better in some cases. Set arc.land.update.default '.
|
||||||
'default.',
|
'to \'rebase\' to make this the default.'),
|
||||||
'conflicts' => array(
|
'conflicts' => array(
|
||||||
'merge' => 'The --merge strategy does not update the feature branch.',
|
'merge' => pht('The --merge strategy does not update the feature '.
|
||||||
'update-with-merge' => 'Cannot be used with --update-with-merge.',
|
'branch.'),
|
||||||
|
'update-with-merge' => pht('Cannot be used with '.
|
||||||
|
'--update-with-merge.'),
|
||||||
),
|
),
|
||||||
'supports' => array(
|
'supports' => array(
|
||||||
'git',
|
'git',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'update-with-merge' => array(
|
'update-with-merge' => array(
|
||||||
'help' => 'When updating the feature branch, use merge instead of '.
|
'help' => pht('When updating the feature branch, use merge instead '.
|
||||||
'rebase. This is the default behavior. '.
|
'of rebase. This is the default behavior. Setting '.
|
||||||
'Setting arc.land.update.default to \'merge\' can also '.
|
'arc.land.update.default to \'merge\' can also be '.
|
||||||
'be used to make this the default.',
|
'used to make this the default.'),
|
||||||
'conflicts' => array(
|
'conflicts' => array(
|
||||||
'merge' => 'The --merge strategy does not update the feature branch.',
|
'merge' => pht('The --merge strategy does not update the feature '.
|
||||||
'update-with-rebase' => 'Cannot be used with --update-with-rebase.',
|
'branch.'),
|
||||||
|
'update-with-rebase' => pht('Cannot be used with '.
|
||||||
|
'--update-with-rebase.'),
|
||||||
),
|
),
|
||||||
'supports' => array(
|
'supports' => array(
|
||||||
'git',
|
'git',
|
||||||
|
@ -152,12 +158,12 @@ EOTEXT
|
||||||
),
|
),
|
||||||
'revision' => array(
|
'revision' => array(
|
||||||
'param' => 'id',
|
'param' => 'id',
|
||||||
'help' => 'Use the message from a specific revision, rather than '.
|
'help' => pht('Use the message from a specific revision, rather than '.
|
||||||
'inferring the revision based on branch content.',
|
'inferring the revision based on branch content.'),
|
||||||
),
|
),
|
||||||
'preview' => array(
|
'preview' => array(
|
||||||
'help' => 'Prints the commits that would be landed. Does not actually '.
|
'help' => pht('Prints the commits that would be landed. Does not '.
|
||||||
'modify or land the commits.'
|
'actually modify or land the commits.'),
|
||||||
),
|
),
|
||||||
'*' => 'branch',
|
'*' => 'branch',
|
||||||
);
|
);
|
||||||
|
@ -204,7 +210,7 @@ EOTEXT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "Done.\n";
|
echo pht('Done.'), "\n";
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -216,7 +222,7 @@ EOTEXT
|
||||||
|
|
||||||
if (!$this->isGit && !$this->isHg) {
|
if (!$this->isGit && !$this->isHg) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"'arc land' only supports git and mercurial.");
|
pht("'arc land' only supports git and mercurial."));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isGit) {
|
if ($this->isGit) {
|
||||||
|
@ -234,14 +240,14 @@ EOTEXT
|
||||||
|
|
||||||
if ($branch) {
|
if ($branch) {
|
||||||
$this->branchType = $this->getBranchType($branch);
|
$this->branchType = $this->getBranchType($branch);
|
||||||
echo "Landing current {$this->branchType} '{$branch}'.\n";
|
echo pht("Landing current %s '%s'.", $this->branchType, $branch), "\n";
|
||||||
$branch = array($branch);
|
$branch = array($branch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($branch) !== 1) {
|
if (count($branch) !== 1) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"Specify exactly one branch or bookmark to land changes from.");
|
pht('Specify exactly one branch or bookmark to land changes from.'));
|
||||||
}
|
}
|
||||||
$this->branch = head($branch);
|
$this->branch = head($branch);
|
||||||
$this->keepBranch = $this->getArgument('keep-branch');
|
$this->keepBranch = $this->getArgument('keep-branch');
|
||||||
|
@ -294,13 +300,16 @@ EOTEXT
|
||||||
$repository_api = $this->getRepositoryAPI();
|
$repository_api = $this->getRepositoryAPI();
|
||||||
|
|
||||||
if ($this->onto == $this->branch) {
|
if ($this->onto == $this->branch) {
|
||||||
$message =
|
$message = pht(
|
||||||
"You can not land a {$this->branchType} onto itself -- you are trying ".
|
"You can not land a %s onto itself -- you are trying ".
|
||||||
"to land '{$this->branch}' onto '{$this->onto}'. For more ".
|
"to land '%s' onto '%s'. For more information on how to push ".
|
||||||
"information on how to push changes, see 'Pushing and Closing ".
|
"changes, see 'Pushing and Closing Revisions' in 'Arcanist User ".
|
||||||
"Revisions' in 'Arcanist User Guide: arc diff' in the documentation.";
|
"Guide: arc diff' in the documentation.",
|
||||||
|
$this->branchType,
|
||||||
|
$this->branch,
|
||||||
|
$this->onto);
|
||||||
if (!$this->isHistoryImmutable()) {
|
if (!$this->isHistoryImmutable()) {
|
||||||
$message .= " You may be able to 'arc amend' instead.";
|
$message .= ' ' . pht("You may be able to 'arc amend' instead.");
|
||||||
}
|
}
|
||||||
throw new ArcanistUsageException($message);
|
throw new ArcanistUsageException($message);
|
||||||
}
|
}
|
||||||
|
@ -309,18 +318,23 @@ EOTEXT
|
||||||
if ($this->useSquash) {
|
if ($this->useSquash) {
|
||||||
if (!$repository_api->supportsRebase()) {
|
if (!$repository_api->supportsRebase()) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"You must enable the rebase extension to use ".
|
pht("You must enable the rebase extension to use the --squash ".
|
||||||
"the --squash strategy.");
|
"strategy."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->branchType != $this->ontoType) {
|
if ($this->branchType != $this->ontoType) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"Source {$this->branch} is a {$this->branchType} but destination ".
|
"Source %s is a %s but destination %s is a %s. When landing a ".
|
||||||
"{$this->onto} is a {$this->ontoType}. When landing a ".
|
"%s, the destination must also be a %s. Use --onto to specify a %s, ".
|
||||||
"{$this->branchType}, the destination must also be a ".
|
"or set arc.land.onto.default in .arcconfig.",
|
||||||
"{$this->branchType}. Use --onto to specify a {$this->branchType}, ".
|
$this->branch,
|
||||||
"or set arc.land.onto.default in .arcconfig.");
|
$this->branchType,
|
||||||
|
$this->onto,
|
||||||
|
$this->ontoType,
|
||||||
|
$this->branchType,
|
||||||
|
$this->branchType,
|
||||||
|
$this->branchType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +345,7 @@ EOTEXT
|
||||||
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"Branch '{$this->branch}' does not exist.");
|
pht("Branch '%s' does not exist.", $this->branch));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,8 +361,10 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(
|
||||||
"Switched to {$this->branchType} **%s**. Identifying and merging...\n",
|
pht("Switched to %s **%s**. Identifying and merging...",
|
||||||
$this->branch);
|
$this->branchType,
|
||||||
|
$this->branch).
|
||||||
|
"\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
private function printPendingCommits() {
|
private function printPendingCommits() {
|
||||||
|
@ -380,10 +396,10 @@ EOTEXT
|
||||||
if (!trim($out)) {
|
if (!trim($out)) {
|
||||||
$this->restoreBranch();
|
$this->restoreBranch();
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"No commits to land from {$this->branch}.");
|
pht("No commits to land from %s.", $this->branch));
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "The following commit(s) will be landed:\n\n{$out}\n";
|
echo pht("The following commit(s) will be landed:\n\n%s", $out), "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private function findRevision() {
|
private function findRevision() {
|
||||||
|
@ -400,7 +416,9 @@ EOTEXT
|
||||||
'ids' => array($revision_id),
|
'ids' => array($revision_id),
|
||||||
));
|
));
|
||||||
if (!$revisions) {
|
if (!$revisions) {
|
||||||
throw new ArcanistUsageException("No such revision 'D{$revision_id}'!");
|
throw new ArcanistUsageException(pht(
|
||||||
|
"No such revision '%s'!",
|
||||||
|
"D{$revision_id}"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$revisions = $repository_api->loadWorkingCopyDifferentialRevisions(
|
$revisions = $repository_api->loadWorkingCopyDifferentialRevisions(
|
||||||
|
@ -409,20 +427,26 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!count($revisions)) {
|
if (!count($revisions)) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"arc can not identify which revision exists on {$this->branchType} ".
|
"arc can not identify which revision exists on %s '%s'. Update the '.
|
||||||
"'{$this->branch}'. Update the revision with recent changes ".
|
'revision with recent changes to synchronize the %s name and hashes, '.
|
||||||
"to synchronize the {$this->branchType} name and hashes, or use ".
|
'or use 'arc amend' to amend the commit message at HEAD, or use ".
|
||||||
"'arc amend' to amend the commit message at HEAD, or use ".
|
"'--revision <id>' to select a revision explicitly.",
|
||||||
"'--revision <id>' to select a revision explicitly.");
|
$this->branchType,
|
||||||
|
$this->branch,
|
||||||
|
$this->branchType));
|
||||||
} else if (count($revisions) > 1) {
|
} else if (count($revisions) > 1) {
|
||||||
$message =
|
$message = pht(
|
||||||
"There are multiple revisions on feature {$this->branchType} ".
|
"There are multiple revisions on feature %s '%s' which are not ".
|
||||||
"'{$this->branch}' which are not present on '{$this->onto}':\n\n".
|
"present on '%s':\n\n".
|
||||||
$this->renderRevisionList($revisions)."\n".
|
"%s\n".
|
||||||
"Separate these revisions onto different {$this->branchType}s, or use ".
|
"Separate these revisions onto different %s, or use --revision <id>' ".
|
||||||
"'--revision <id>' to use the commit message from <id> and land them ".
|
"to use the commit message from <id> and land them all.",
|
||||||
"all.";
|
$this->branchType,
|
||||||
|
$this->branch,
|
||||||
|
$this->onto,
|
||||||
|
$this->renderRevisionList($revisions),
|
||||||
|
$this->branchType.'s');
|
||||||
throw new ArcanistUsageException($message);
|
throw new ArcanistUsageException($message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,18 +465,21 @@ EOTEXT
|
||||||
));
|
));
|
||||||
$other_author = ipull($other_author, 'userName', 'phid');
|
$other_author = ipull($other_author, 'userName', 'phid');
|
||||||
$other_author = $other_author[$this->revision['authorPHID']];
|
$other_author = $other_author[$this->revision['authorPHID']];
|
||||||
$ok = phutil_console_confirm(
|
$ok = phutil_console_confirm(pht(
|
||||||
"This {$this->branchType} has revision 'D{$rev_id}: {$rev_title}' ".
|
"This %s has revision '%s' but you are not the author. Land this ".
|
||||||
"but you are not the author. Land this revision by {$other_author}?");
|
"revision by %s?",
|
||||||
|
$this->branchType,
|
||||||
|
"D{$rev_id}: {$rev_title}",
|
||||||
|
$other_author));
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new ArcanistUserAbortException();
|
throw new ArcanistUserAbortException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($rev_status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
if ($rev_status != ArcanistDifferentialRevisionStatus::ACCEPTED) {
|
||||||
$ok = phutil_console_confirm(
|
$ok = phutil_console_confirm(pht(
|
||||||
"Revision 'D{$rev_id}: {$rev_title}' has not been ".
|
"Revision '%s' has not been accepted. Contine anyway?",
|
||||||
"accepted. Continue anyway?");
|
"D{$rev_id}: {$rev_title}"));
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new ArcanistUserAbortException();
|
throw new ArcanistUserAbortException();
|
||||||
}
|
}
|
||||||
|
@ -483,11 +510,11 @@ EOTEXT
|
||||||
}
|
}
|
||||||
$open_revs = implode("\n", $open_revs);
|
$open_revs = implode("\n", $open_revs);
|
||||||
|
|
||||||
echo "Revision 'D{$rev_id}: {$rev_title}' depends ".
|
echo pht("Revision '%s' depends on open revisions:\n\n%s",
|
||||||
"on open revisions:\n\n";
|
"D{$rev_id}: {$rev_title}",
|
||||||
echo $open_revs;
|
$open_revs);
|
||||||
|
|
||||||
$ok = phutil_console_confirm("Continue anyway?");
|
$ok = phutil_console_confirm(pht("Continue anyway?"));
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new ArcanistUserAbortException();
|
throw new ArcanistUserAbortException();
|
||||||
}
|
}
|
||||||
|
@ -504,8 +531,8 @@ EOTEXT
|
||||||
$this->messageFile = new TempFile();
|
$this->messageFile = new TempFile();
|
||||||
Filesystem::writeFile($this->messageFile, $message);
|
Filesystem::writeFile($this->messageFile, $message);
|
||||||
|
|
||||||
echo "Landing revision 'D{$rev_id}: ".
|
echo pht("Landing revision '%s'...",
|
||||||
"{$rev_title}'...\n";
|
"D{$rev_id}: {$rev_title}"), "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
private function pullFromRemote() {
|
private function pullFromRemote() {
|
||||||
|
@ -515,9 +542,9 @@ EOTEXT
|
||||||
if ($this->isGit) {
|
if ($this->isGit) {
|
||||||
$repository_api->execxLocal('checkout %s', $this->onto);
|
$repository_api->execxLocal('checkout %s', $this->onto);
|
||||||
|
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(pht(
|
||||||
"Switched to branch **%s**. Updating branch...\n",
|
"Switched to branch **%s**. Updating branch...\n",
|
||||||
$this->onto);
|
$this->onto));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$repository_api->execxLocal('pull --ff-only --no-stat');
|
$repository_api->execxLocal('pull --ff-only --no-stat');
|
||||||
|
@ -525,32 +552,34 @@ EOTEXT
|
||||||
if (!$this->isGitSvn) {
|
if (!$this->isGitSvn) {
|
||||||
throw $ex;
|
throw $ex;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
list($out) = $repository_api->execxLocal(
|
list($out) = $repository_api->execxLocal(
|
||||||
'log %s..%s',
|
'log %s..%s',
|
||||||
$this->ontoRemoteBranch,
|
$this->ontoRemoteBranch,
|
||||||
$this->onto);
|
$this->onto);
|
||||||
if (strlen(trim($out))) {
|
if (strlen(trim($out))) {
|
||||||
$local_ahead_of_remote = true;
|
$local_ahead_of_remote = true;
|
||||||
} else {
|
} else if ($this->isGitSvn) {
|
||||||
$repository_api->execxLocal('svn rebase');
|
$repository_api->execxLocal('svn rebase');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
} else if ($this->isHg) {
|
} else if ($this->isHg) {
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(pht(
|
||||||
"Updating **%s**...\n",
|
"Updating **%s**...",
|
||||||
$this->onto);
|
$this->onto) . "\n");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
list($out, $err) = $repository_api->execxLocal('pull');
|
list($out, $err) = $repository_api->execxLocal('pull');
|
||||||
|
|
||||||
$divergedbookmark = $this->onto.'@'.$repository_api->getBranchName();
|
$divergedbookmark = $this->onto.'@'.$repository_api->getBranchName();
|
||||||
if (strpos($err, $divergedbookmark) !== false) {
|
if (strpos($err, $divergedbookmark) !== false) {
|
||||||
throw new ArcanistUsageException(phutil_console_format(
|
throw new ArcanistUsageException(phutil_console_format(pht(
|
||||||
"Local bookmark **{$this->onto}** has diverged from the ".
|
"Local bookmark **%s** has diverged from the server's **%s** ".
|
||||||
"server's **{$this->onto}** (now labeled ".
|
"(now labeled **%s**). Please resolve this divergence and run ".
|
||||||
"**{$divergedbookmark}**). Please resolve this divergence and ".
|
"'arc land' again.",
|
||||||
"run 'arc land' again."));
|
$this->onto,
|
||||||
|
$this->onto,
|
||||||
|
$divergedbookmark)));
|
||||||
}
|
}
|
||||||
} catch (CommandException $ex) {
|
} catch (CommandException $ex) {
|
||||||
$err = $ex->getError();
|
$err = $ex->getError();
|
||||||
|
@ -601,11 +630,16 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($local_ahead_of_remote) {
|
if ($local_ahead_of_remote) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"Local {$this->ontoType} '{$this->onto}' is ahead of remote ".
|
"Local %s '%s' is ahead of remote %s '%s', so landing a feature ".
|
||||||
"{$this->ontoType} '{$this->ontoRemoteBranch}', so landing a feature ".
|
"%s would push additional changes. Push or reset the changes in '%s' ".
|
||||||
"{$this->ontoType} would push additional changes. Push or reset the ".
|
"before running 'arc land'.",
|
||||||
"changes in '{$this->onto}' before running 'arc land'.");
|
$this->ontoType,
|
||||||
|
$this->onto,
|
||||||
|
$this->ontoType,
|
||||||
|
$this->ontoRemoteBranch,
|
||||||
|
$this->ontoType,
|
||||||
|
$this->onto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -615,33 +649,34 @@ EOTEXT
|
||||||
chdir($repository_api->getPath());
|
chdir($repository_api->getPath());
|
||||||
if ($this->isGit) {
|
if ($this->isGit) {
|
||||||
if ($this->shouldUpdateWithRebase) {
|
if ($this->shouldUpdateWithRebase) {
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(pht(
|
||||||
"Rebasing **%s** onto **%s**\n",
|
"Rebasing **%s** onto **%s**",
|
||||||
$this->branch,
|
$this->branch,
|
||||||
$this->onto);
|
$this->onto)."\n");
|
||||||
$err = phutil_passthru('git rebase %s', $this->onto);
|
$err = phutil_passthru('git rebase %s', $this->onto);
|
||||||
if ($err) {
|
if ($err) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'git rebase {$this->onto}' failed. ".
|
"'git rebase %s' failed. You can abort with 'git rebase ".
|
||||||
"You can abort with 'git rebase --abort', ".
|
"--abort', or resolve conflicts and use 'git rebase --continue' ".
|
||||||
"or resolve conflicts and use 'git rebase ".
|
"to continue forward. After resolving the rebase, run 'arc land' ".
|
||||||
"--continue' to continue forward. After resolving the rebase, ".
|
"again.",
|
||||||
"run 'arc land' again.");
|
$this->onto));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(pht(
|
||||||
"Merging **%s** into **%s**\n",
|
"Merging **%s** into **%s**",
|
||||||
$this->branch,
|
$this->branch,
|
||||||
$this->onto);
|
$this->onto)."\n");
|
||||||
$err = phutil_passthru(
|
$err = phutil_passthru(
|
||||||
'git merge --no-stat %s -m %s',
|
'git merge --no-stat %s -m %s',
|
||||||
$this->onto,
|
$this->onto,
|
||||||
"Automatic merge by 'arc land'");
|
pht("Automatic merge by 'arc land'"));
|
||||||
if ($err) {
|
if ($err) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'git merge {$this->onto}' failed. ".
|
"'git merge %s' failed. ".
|
||||||
"To continue: resolve the conflicts, commit the changes, then run ".
|
"To continue: resolve the conflicts, commit the changes, then run ".
|
||||||
"'arc land' again. To abort: run 'git merge --abort'.");
|
"'arc land' again. To abort: run 'git merge --abort'.",
|
||||||
|
$this->onto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ($this->isHg) {
|
} else if ($this->isHg) {
|
||||||
|
@ -662,11 +697,13 @@ EOTEXT
|
||||||
$repository_api->execManualLocal(
|
$repository_api->execManualLocal(
|
||||||
'rebase --abort');
|
'rebase --abort');
|
||||||
$this->restoreBranch();
|
$this->restoreBranch();
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'hg rebase {$this->onto}' failed and the rebase was aborted. ".
|
"'hg rebase %s' failed and the rebase was aborted. ".
|
||||||
"This is most likely due to conflicts. Manually rebase ".
|
"This is most likely due to conflicts. Manually rebase %s onto ".
|
||||||
"{$this->branch} onto {$this->onto}, resolve the conflicts, ".
|
"%s, resolve the conflicts, then run 'arc land' again.",
|
||||||
"then run 'arc land' again.");
|
$this->onto,
|
||||||
|
$this->branch,
|
||||||
|
$this->onto));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -816,12 +853,16 @@ EOTEXT
|
||||||
|
|
||||||
$alt_count = count($alt_branches);
|
$alt_count = count($alt_branches);
|
||||||
if ($alt_count > 0) {
|
if ($alt_count > 0) {
|
||||||
$input = phutil_console_prompt(
|
$input = phutil_console_prompt(pht(
|
||||||
ucfirst($this->branchType)." '{$this->branch}' has {$alt_count} ".
|
"%s '%s' has %s %s(s) forking off of it that would be deleted ".
|
||||||
"{$this->branchType}(s) forking off of it that would be deleted ".
|
|
||||||
"during a squash. Would you like to keep a non-squashed copy, rebase ".
|
"during a squash. Would you like to keep a non-squashed copy, rebase ".
|
||||||
"them on top of '{$this->branch}', or abort and deal with them ".
|
"them on top of '%s', or abort and deal with them yourself? ".
|
||||||
"yourself? (k)eep, (r)ebase, (a)bort:");
|
"(k)eep, (r)ebase, (a)bort:",
|
||||||
|
ucfirst($this->branchType),
|
||||||
|
$this->branch,
|
||||||
|
$alt_count,
|
||||||
|
$this->branchType,
|
||||||
|
$this->branch));
|
||||||
|
|
||||||
if ($input == 'k' || $input == 'keep') {
|
if ($input == 'k' || $input == 'keep') {
|
||||||
$this->keepBranch = true;
|
$this->keepBranch = true;
|
||||||
|
@ -834,11 +875,17 @@ EOTEXT
|
||||||
}
|
}
|
||||||
} else if ($input == 'a' || $input == 'abort') {
|
} else if ($input == 'a' || $input == 'abort') {
|
||||||
$branch_string = implode("\n", $alt_branches);
|
$branch_string = implode("\n", $alt_branches);
|
||||||
echo "\nRemove the {$this->branchType}s starting at these revisions ".
|
echo
|
||||||
"and run arc land again:\n{$branch_string}\n\n";
|
"\n",
|
||||||
|
pht("Remove the %s starting at these revisions and ".
|
||||||
|
"run arc land again:\n%s",
|
||||||
|
$this->branchType.'s',
|
||||||
|
$branch_string),
|
||||||
|
"\n\n";
|
||||||
throw new ArcanistUserAbortException();
|
throw new ArcanistUserAbortException();
|
||||||
} else {
|
} else {
|
||||||
throw new ArcanistUsageException("Invalid choice. Aborting arc land.");
|
throw new ArcanistUsageException(
|
||||||
|
pht("Invalid choice. Aborting arc land."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -857,10 +904,10 @@ EOTEXT
|
||||||
$this->branch);
|
$this->branch);
|
||||||
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'git merge' failed. Your working copy has been left in a partially ".
|
"'git merge' failed. Your working copy has been left in a partially ".
|
||||||
"merged state. You can: abort with 'git merge --abort'; or follow ".
|
"merged state. You can: abort with 'git merge --abort'; or follow ".
|
||||||
"the instructions to complete the merge.");
|
"the instructions to complete the merge."));
|
||||||
}
|
}
|
||||||
} else if ($this->isHg) {
|
} else if ($this->isHg) {
|
||||||
// HG arc land currently doesn't support --merge.
|
// HG arc land currently doesn't support --merge.
|
||||||
|
@ -870,8 +917,8 @@ EOTEXT
|
||||||
// until there is a demand for it.
|
// until there is a demand for it.
|
||||||
// The user should never reach this line, since --merge is
|
// The user should never reach this line, since --merge is
|
||||||
// forbidden at the command line argument level.
|
// forbidden at the command line argument level.
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"--merge is not currently supported for hg repos.");
|
"--merge is not currently supported for hg repos."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,11 +951,11 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->getArgument('hold')) {
|
if ($this->getArgument('hold')) {
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(pht(
|
||||||
"Holding change in **%s**: it has NOT been pushed yet.\n",
|
"Holding change in **%s**: it has NOT been pushed yet.",
|
||||||
$this->onto);
|
$this->onto). "\n");
|
||||||
} else {
|
} else {
|
||||||
echo "Pushing change...\n\n";
|
echo pht('Pushing change...'), "\n\n";
|
||||||
|
|
||||||
chdir($repository_api->getPath());
|
chdir($repository_api->getPath());
|
||||||
|
|
||||||
|
@ -938,14 +985,17 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
echo phutil_console_format("<bg:red>** PUSH FAILED! **</bg>\n");
|
$failed_str = pht('PUSH FAILED!');
|
||||||
|
echo phutil_console_format("<bg:red>** %s **</bg>\n", $failed_str);
|
||||||
$this->executeCleanupAfterFailedPush();
|
$this->executeCleanupAfterFailedPush();
|
||||||
if ($this->isGit) {
|
if ($this->isGit) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'{$cmd}' failed! Fix the error and run 'arc land' again.");
|
"'%s' failed! Fix the error and run 'arc land' again.",
|
||||||
|
$cmd));
|
||||||
}
|
}
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(pht(
|
||||||
"'{$cmd}' failed! Fix the error and push this change manually.");
|
"'%s' failed! Fix the error and push this change manually.",
|
||||||
|
$cmd));
|
||||||
}
|
}
|
||||||
|
|
||||||
$mark_workflow = $this->buildChildWorkflow(
|
$mark_workflow = $this->buildChildWorkflow(
|
||||||
|
@ -977,7 +1027,7 @@ EOTEXT
|
||||||
private function cleanupBranch() {
|
private function cleanupBranch() {
|
||||||
$repository_api = $this->getRepositoryAPI();
|
$repository_api = $this->getRepositoryAPI();
|
||||||
|
|
||||||
echo "Cleaning up feature {$this->branchType}...\n";
|
echo pht('Cleaning up feature %s...', $this->branchType), "\n";
|
||||||
if ($this->isGit) {
|
if ($this->isGit) {
|
||||||
list($ref) = $repository_api->execxLocal(
|
list($ref) = $repository_api->execxLocal(
|
||||||
'rev-parse --verify %s',
|
'rev-parse --verify %s',
|
||||||
|
@ -987,7 +1037,7 @@ EOTEXT
|
||||||
'git checkout -b %s %s',
|
'git checkout -b %s %s',
|
||||||
$this->branch,
|
$this->branch,
|
||||||
$ref);
|
$ref);
|
||||||
echo "(Use `{$recovery_command}` if you want it back.)\n";
|
echo pht('(Use `%s` if you want it back.)', $recovery_command), "\n";
|
||||||
$repository_api->execxLocal(
|
$repository_api->execxLocal(
|
||||||
'branch -D %s',
|
'branch -D %s',
|
||||||
$this->branch);
|
$this->branch);
|
||||||
|
@ -1022,7 +1072,8 @@ EOTEXT
|
||||||
$this->branch);
|
$this->branch);
|
||||||
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
echo "No remote feature {$this->branchType} to clean up.\n";
|
echo pht('No remote feature %s to clean up.',
|
||||||
|
$this->branchType), "\n";
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// NOTE: In Git, you delete a remote branch by pushing it with a
|
// NOTE: In Git, you delete a remote branch by pushing it with a
|
||||||
|
@ -1030,7 +1081,7 @@ EOTEXT
|
||||||
//
|
//
|
||||||
// git push <remote> :<branch>
|
// git push <remote> :<branch>
|
||||||
|
|
||||||
echo "Cleaning up remote feature branch...\n";
|
echo pht('Cleaning up remote feature %s...', $this->branchType), "\n";
|
||||||
$repository_api->execxLocal(
|
$repository_api->execxLocal(
|
||||||
'push %s :%s',
|
'push %s :%s',
|
||||||
$this->remote,
|
$this->remote,
|
||||||
|
|
Loading…
Reference in a new issue