mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-26 08:42:40 +01:00
Update 'arc land': add --squash, add default config, fix windows compat
Summary: - We have "--merge", added similar "--squash" for completeness. - Switched away from (cd .. && ...) pattern which is not functional on Windows. - Allow a default --onto to be specified, if master isn't the best default for a project. Test Plan: - Did --hold --keep dry runs, changes landed properly. - Set a default onto branch in .arcconfig. - Ran --merge and --squash together to verify conflict configuration. Reviewers: btrahan CC: aran, epriestley Maniphest Tasks: T124, T1033 Differential Revision: https://secure.phabricator.com/D2001
This commit is contained in:
parent
3bff9417e9
commit
e31bc81b6c
1 changed files with 50 additions and 49 deletions
|
@ -68,7 +68,8 @@ EOTEXT
|
||||||
'onto' => array(
|
'onto' => array(
|
||||||
'param' => 'master',
|
'param' => 'master',
|
||||||
'help' => "Land feature branch onto a branch other than ".
|
'help' => "Land feature branch onto a branch other than ".
|
||||||
"'master' (default).",
|
"'master' (default). You can change the default by setting ".
|
||||||
|
"'arc.land.onto.default' in your .arcconfig.",
|
||||||
),
|
),
|
||||||
'hold' => array(
|
'hold' => array(
|
||||||
'help' => "Prepare the change to be pushed, but do not actually ".
|
'help' => "Prepare the change to be pushed, but do not actually ".
|
||||||
|
@ -87,6 +88,14 @@ EOTEXT
|
||||||
'project is marked as having an immutable history, this is '.
|
'project is marked as having an immutable history, this is '.
|
||||||
'the default behavior.',
|
'the default behavior.',
|
||||||
),
|
),
|
||||||
|
'squash' => array(
|
||||||
|
'help' => 'Perform a --squash merge, not a --no-ff merge. If the '.
|
||||||
|
'project is marked as having a mutable history, this is '.
|
||||||
|
'the default behavior.',
|
||||||
|
'conflicts' => array(
|
||||||
|
'merge' => '--merge and --squash are conflicting merge strategies.',
|
||||||
|
),
|
||||||
|
),
|
||||||
'revision' => array(
|
'revision' => array(
|
||||||
'param' => 'id',
|
'param' => 'id',
|
||||||
'help' => 'Use the message from a specific revision, rather than '.
|
'help' => 'Use the message from a specific revision, rather than '.
|
||||||
|
@ -104,19 +113,28 @@ EOTEXT
|
||||||
}
|
}
|
||||||
$branch = head($branch);
|
$branch = head($branch);
|
||||||
|
|
||||||
|
$onto_default = nonempty(
|
||||||
|
$this->getWorkingCopy()->getConfig('arc.land.onto.default'),
|
||||||
|
'master');
|
||||||
|
|
||||||
$remote = $this->getArgument('remote', 'origin');
|
$remote = $this->getArgument('remote', 'origin');
|
||||||
$onto = $this->getArgument('onto', 'master');
|
$onto = $this->getArgument('onto', $onto_default);
|
||||||
$is_immutable = $this->isHistoryImmutable() ||
|
|
||||||
$this->getArgument('merge');
|
if ($this->getArgument('merge')) {
|
||||||
|
$use_squash = false;
|
||||||
|
} else if ($this->getArgument('squash')) {
|
||||||
|
$use_squash = true;
|
||||||
|
} else {
|
||||||
|
$use_squash = !$this->isHistoryImmutable();
|
||||||
|
}
|
||||||
|
|
||||||
$repository_api = $this->getRepositoryAPI();
|
$repository_api = $this->getRepositoryAPI();
|
||||||
if (!($repository_api instanceof ArcanistGitAPI)) {
|
if (!($repository_api instanceof ArcanistGitAPI)) {
|
||||||
throw new ArcanistUsageException("'arc land' only supports git.");
|
throw new ArcanistUsageException("'arc land' only supports git.");
|
||||||
}
|
}
|
||||||
|
|
||||||
list($err) = exec_manual(
|
list($err) = $repository_api->execManualLocal(
|
||||||
'(cd %s && git rev-parse --verify %s)',
|
'rev-parse --verify %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$branch);
|
$branch);
|
||||||
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
|
@ -128,22 +146,16 @@ EOTEXT
|
||||||
|
|
||||||
$old_branch = $repository_api->getBranchName();
|
$old_branch = $repository_api->getBranchName();
|
||||||
|
|
||||||
execx(
|
$repository_api->execxLocal('checkout %s', $onto);
|
||||||
'(cd %s && git checkout %s)',
|
|
||||||
$repository_api->getPath(),
|
|
||||||
$onto);
|
|
||||||
|
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(
|
||||||
"Switched to branch **%s**. Updating branch...\n",
|
"Switched to branch **%s**. Updating branch...\n",
|
||||||
$onto);
|
$onto);
|
||||||
|
|
||||||
execx(
|
$repository_api->execxLocal('pull --ff-only');
|
||||||
'(cd %s && git pull --ff-only)',
|
|
||||||
$repository_api->getPath());
|
|
||||||
|
|
||||||
list($out) = execx(
|
list($out) = $repository_api->execxLocal(
|
||||||
'(cd %s && git log %s/%s..%s)',
|
'log %s/%s..%s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$remote,
|
$remote,
|
||||||
$onto,
|
$onto,
|
||||||
$onto);
|
$onto);
|
||||||
|
@ -154,20 +166,17 @@ EOTEXT
|
||||||
"changes in '{$onto}' before running 'arc land'.");
|
"changes in '{$onto}' before running 'arc land'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
execx(
|
$repository_api->execxLocal(
|
||||||
'(cd %s && git checkout %s)',
|
'checkout %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$branch);
|
$branch);
|
||||||
|
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(
|
||||||
"Switched to branch **%s**. Identifying and merging...\n",
|
"Switched to branch **%s**. Identifying and merging...\n",
|
||||||
$branch);
|
$branch);
|
||||||
|
|
||||||
if (!$is_immutable) {
|
if ($use_squash) {
|
||||||
$err = phutil_passthru(
|
chdir($repository_api->getPath());
|
||||||
'(cd %s && git rebase %s)',
|
$err = phutil_passthru('git rebase %s', $onto);
|
||||||
$repository_api->getPath(),
|
|
||||||
$onto);
|
|
||||||
if ($err) {
|
if ($err) {
|
||||||
throw new ArcanistUsageException(
|
throw new ArcanistUsageException(
|
||||||
"'git rebase {$onto}' failed. You can abort with 'git rebase ".
|
"'git rebase {$onto}' failed. You can abort with 'git rebase ".
|
||||||
|
@ -237,17 +246,14 @@ EOTEXT
|
||||||
'revision_id' => $revision['id'],
|
'revision_id' => $revision['id'],
|
||||||
));
|
));
|
||||||
|
|
||||||
execx(
|
$repository_api->execxLocal('checkout %s', $onto);
|
||||||
'(cd %s && git checkout %s)',
|
|
||||||
$repository_api->getPath(),
|
|
||||||
$onto);
|
|
||||||
|
|
||||||
if ($is_immutable) {
|
if ($use_squash) {
|
||||||
// In immutable histories, do a --no-ff merge to force a merge commit with
|
// In immutable histories, do a --no-ff merge to force a merge commit with
|
||||||
// the right message.
|
// the right message.
|
||||||
|
chdir($repository_api->getPath());
|
||||||
$err = phutil_passthru(
|
$err = phutil_passthru(
|
||||||
'(cd %s && git merge --no-ff -m %s %s)',
|
'git merge --no-ff -m %s %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$message,
|
$message,
|
||||||
$branch);
|
$branch);
|
||||||
if ($err) {
|
if ($err) {
|
||||||
|
@ -258,13 +264,11 @@ EOTEXT
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// In mutable histories, do a --squash merge.
|
// In mutable histories, do a --squash merge.
|
||||||
execx(
|
$repository_api->execxLocal(
|
||||||
'(cd %s && git merge --squash --ff-only %s)',
|
'merge --squash --ff-only %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$branch);
|
$branch);
|
||||||
execx(
|
$repository_api->execxLocal(
|
||||||
'(cd %s && git commit -m %s)',
|
'commit -m %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$message);
|
$message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,9 +279,9 @@ EOTEXT
|
||||||
} else {
|
} else {
|
||||||
echo "Pushing change...\n\n";
|
echo "Pushing change...\n\n";
|
||||||
|
|
||||||
|
chdir($repository_api->getPath());
|
||||||
$err = phutil_passthru(
|
$err = phutil_passthru(
|
||||||
'(cd %s && git push %s %s)',
|
'git push %s %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$remote,
|
$remote,
|
||||||
$onto);
|
$onto);
|
||||||
|
|
||||||
|
@ -298,9 +302,8 @@ EOTEXT
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->getArgument('keep-branch')) {
|
if (!$this->getArgument('keep-branch')) {
|
||||||
list($ref) = execx(
|
list($ref) = $repository_api->execxLocal(
|
||||||
'(cd %s && git rev-parse --verify %s)',
|
'rev-parse --verify %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$branch);
|
$branch);
|
||||||
$ref = trim($ref);
|
$ref = trim($ref);
|
||||||
$recovery_command = csprintf(
|
$recovery_command = csprintf(
|
||||||
|
@ -310,18 +313,16 @@ EOTEXT
|
||||||
|
|
||||||
echo "Cleaning up feature branch...\n";
|
echo "Cleaning up feature branch...\n";
|
||||||
echo "(Use `{$recovery_command}` if you want it back.)\n";
|
echo "(Use `{$recovery_command}` if you want it back.)\n";
|
||||||
execx(
|
$repository_api->execxLocal(
|
||||||
'(cd %s && git branch -D %s)',
|
'branch -D %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$branch);
|
$branch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we were on some branch A and the user ran "arc land B", switch back
|
// If we were on some branch A and the user ran "arc land B", switch back
|
||||||
// to A.
|
// to A.
|
||||||
if (($old_branch != $branch) && ($old_branch != $onto)) {
|
if (($old_branch != $branch) && ($old_branch != $onto)) {
|
||||||
execx(
|
$repository_api->execxLocal(
|
||||||
'(cd %s && git checkout %s)',
|
'checkout %s',
|
||||||
$repository_api->getPath(),
|
|
||||||
$old_branch);
|
$old_branch);
|
||||||
echo phutil_console_format(
|
echo phutil_console_format(
|
||||||
"Switched back to branch **%s**.\n",
|
"Switched back to branch **%s**.\n",
|
||||||
|
|
Loading…
Reference in a new issue