Changeset View
Changeset View
Standalone View
Standalone View
src/workflow/ArcanistPatchWorkflow.php
Show First 20 Lines • Show All 301 Lines • ▼ Show 20 Lines | if ($repository_api instanceof ArcanistGitAPI) { | ||||
$repository_api->execxLocal( | $repository_api->execxLocal( | ||||
'checkout -b %s %s', | 'checkout -b %s %s', | ||||
$branch_name, | $branch_name, | ||||
$base_revision); | $base_revision); | ||||
} else { | } else { | ||||
$repository_api->execxLocal('checkout -b %s', $branch_name); | $repository_api->execxLocal('checkout -b %s', $branch_name); | ||||
} | } | ||||
// Synchronize submodule state, since the checkout may have modified | |||||
// submodule references. See PHI1083. | |||||
// Note that newer versions of "git checkout" include a | |||||
// "--recurse-submodules" flag which accomplishes this goal a little | |||||
// more simply. For now, use the more compatible form. | |||||
$repository_api->execPassthru('submodule update --init --recursive'); | |||||
echo phutil_console_format( | echo phutil_console_format( | ||||
"%s\n", | "%s\n", | ||||
pht( | pht( | ||||
'Created and checked out branch %s.', | 'Created and checked out branch %s.', | ||||
$branch_name)); | $branch_name)); | ||||
} else if ($repository_api instanceof ArcanistMercurialAPI) { | } else if ($repository_api instanceof ArcanistMercurialAPI) { | ||||
$branch_name = $this->getBookmarkName($bundle); | $branch_name = $this->getBookmarkName($bundle); | ||||
$base_revision = $bundle->getBaseRevision(); | $base_revision = $bundle->getBaseRevision(); | ||||
▲ Show 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | if ($repository_api instanceof ArcanistSubversionAPI) { | ||||
// NOTE: Git patches may fail if they change the case of a filename | // NOTE: Git patches may fail if they change the case of a filename | ||||
// (for instance, from 'example.c' to 'Example.c'). As of now, Git | // (for instance, from 'example.c' to 'Example.c'). As of now, Git | ||||
// can not apply these patches on case-insensitive filesystems and | // can not apply these patches on case-insensitive filesystems and | ||||
// there is no way to build a patch which works. | // there is no way to build a patch which works. | ||||
throw new ArcanistUsageException(pht('Unable to apply patch!')); | throw new ArcanistUsageException(pht('Unable to apply patch!')); | ||||
} | } | ||||
// See PHI1083 and PHI648. If the patch applied changes to submodules, | |||||
// it only updates the submodule pointer, not the actual submodule. We're | |||||
// left with the pointer update staged in the index, and the unmodified | |||||
// submodule on disk. | |||||
// If we then "git commit --all" or "git add --all", the unmodified | |||||
// submodule on disk is added to the index as a change, which effectively | |||||
// undoes the patch we just applied and reverts the submodule back to | |||||
// the previous state. | |||||
// To avoid this, do a submodule update before we continue. | |||||
// We could also possibly skip the "--all" flag so we don't have to do | |||||
// this submodule update, but we want to leave the working copy in a | |||||
// clean state anyway, so we're going to have to do an update at some | |||||
// point. This usually doesn't cost us anything. | |||||
$repository_api->execPassthru('submodule update --init --recursive'); | |||||
if ($this->shouldCommit()) { | if ($this->shouldCommit()) { | ||||
if ($bundle->getFullAuthor()) { | if ($bundle->getFullAuthor()) { | ||||
$author_cmd = csprintf('--author=%s', $bundle->getFullAuthor()); | $author_cmd = csprintf('--author=%s', $bundle->getFullAuthor()); | ||||
} else { | } else { | ||||
$author_cmd = ''; | $author_cmd = ''; | ||||
} | } | ||||
$commit_message = $this->getCommitMessage($bundle); | $commit_message = $this->getCommitMessage($bundle); | ||||
$future = $repository_api->execFutureLocal( | $future = $repository_api->execFutureLocal( | ||||
'commit -a %C -F - --no-verify', | 'commit -a %C -F - --no-verify', | ||||
$author_cmd); | $author_cmd); | ||||
$future->write($commit_message); | $future->write($commit_message); | ||||
$future->resolvex(); | $future->resolvex(); | ||||
$verb = pht('committed'); | $verb = pht('committed'); | ||||
} else { | } else { | ||||
$verb = pht('applied'); | $verb = pht('applied'); | ||||
} | } | ||||
if ($this->canBranch() && | if ($this->canBranch() && | ||||
!$this->shouldBranch() && | !$this->shouldBranch() && | ||||
$this->shouldCommit() && $has_base_revision) { | $this->shouldCommit() && $has_base_revision) { | ||||
// See PHI1083 and PHI648. Synchronize submodule state after mutating | |||||
// the working copy. | |||||
$repository_api->execxLocal('checkout %s', $original_branch); | $repository_api->execxLocal('checkout %s', $original_branch); | ||||
$repository_api->execPassthru('submodule update --init --recursive'); | |||||
$ex = null; | $ex = null; | ||||
try { | try { | ||||
$repository_api->execxLocal('cherry-pick %s', $new_branch); | $repository_api->execxLocal('cherry-pick %s', $new_branch); | ||||
$repository_api->execPassthru('submodule update --init --recursive'); | |||||
} catch (Exception $ex) { | } catch (Exception $ex) { | ||||
// do nothing | // do nothing | ||||
} | } | ||||
$repository_api->execxLocal('branch -D %s', $new_branch); | $repository_api->execxLocal('branch -D %s', $new_branch); | ||||
if ($ex) { | if ($ex) { | ||||
echo phutil_console_format( | echo phutil_console_format( | ||||
"\n<bg:red>** %s**</bg>\n", | "\n<bg:red>** %s**</bg>\n", | ||||
pht('Cherry Pick Failed!')); | pht('Cherry Pick Failed!')); | ||||
throw $ex; | throw $ex; | ||||
} | } | ||||
} | } | ||||
// Synchronize submodule state, since the patch may have made changes | |||||
// to ".gitmodules". We do this after we finish managing branches so | |||||
// the behavior is correct under "--nobranch"; see PHI648. | |||||
$repository_api->execPassthru('submodule update --init --recursive'); | |||||
echo phutil_console_format( | echo phutil_console_format( | ||||
"<bg:green>** %s **</bg> %s\n", | "<bg:green>** %s **</bg> %s\n", | ||||
pht('OKAY'), | pht('OKAY'), | ||||
pht('Successfully %s patch.', $verb)); | pht('Successfully %s patch.', $verb)); | ||||
} else if ($repository_api instanceof ArcanistMercurialAPI) { | } else if ($repository_api instanceof ArcanistMercurialAPI) { | ||||
$future = $repository_api->execFutureLocal('import --no-commit -'); | $future = $repository_api->execFutureLocal('import --no-commit -'); | ||||
$future->write($bundle->toGitPatch()); | $future->write($bundle->toGitPatch()); | ||||
▲ Show 20 Lines • Show All 347 Lines • Show Last 20 Lines |