diff --git a/src/land/ArcanistGitLandEngine.php b/src/land/ArcanistGitLandEngine.php --- a/src/land/ArcanistGitLandEngine.php +++ b/src/land/ArcanistGitLandEngine.php @@ -473,8 +473,9 @@ private function destroyLocalBranch() { $api = $this->getRepositoryAPI(); + $source_ref = $this->getSourceRef(); - if ($this->getSourceRef() == $this->getTargetOnto()) { + if ($source_ref == $this->getTargetOnto()) { // If we landed a branch into a branch with the same name, so don't // destroy it. This prevents us from cleaning up "master" if you're // landing master into itself. @@ -483,20 +484,32 @@ // TODO: Maybe this should also recover the proper upstream? + // See T10321. If we were not landing a branch, don't try to clean it up. + // This happens most often when landing from a detached HEAD. + $is_branch = $this->isBranch($source_ref); + if (!$is_branch) { + echo tsprintf( + "%s\n", + pht( + '(Source "%s" is not a branch, leaving working copy as-is.)', + $source_ref)); + return; + } + $recovery_command = csprintf( 'git checkout -b %R %R', - $this->getSourceRef(), + $source_ref, $this->sourceCommit); echo tsprintf( "%s\n", - pht('Cleaning up branch "%s"...', $this->getSourceRef())); + pht('Cleaning up branch "%s"...', $source_ref)); echo tsprintf( "%s\n", pht('(Use `%s` if you want it back.)', $recovery_command)); - $api->execxLocal('branch -D -- %s', $this->getSourceRef()); + $api->execxLocal('branch -D -- %s', $source_ref); } /** @@ -592,4 +605,14 @@ 'same state as before.')); } + private function isBranch($ref) { + $api = $this->getRepositoryAPI(); + + list($err) = $api->execManualLocal( + 'show-ref --verify --quiet -- %R', + 'refs/heads/'.$ref); + + return !$err; + } + }