1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-26 00:32:41 +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:
epriestley 2012-03-22 18:20:22 -07:00
parent 3bff9417e9
commit e31bc81b6c

View file

@ -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",