diff --git a/dev-infra/pr/discover-new-conflicts/index.ts b/dev-infra/pr/discover-new-conflicts/index.ts index daa1873092..790d809438 100644 --- a/dev-infra/pr/discover-new-conflicts/index.ts +++ b/dev-infra/pr/discover-new-conflicts/index.ts @@ -63,8 +63,8 @@ export async function discoverNewConflictsForPr( process.exit(1); } - /** The active github branch when the run began. */ - const originalBranch = git.getCurrentBranch(); + /** The active github branch or revision before we performed any Git commands. */ + const previousBranchOrRevision = git.getCurrentBranchOrRevision(); /* Progress bar to indicate progress. */ const progressBar = new Bar({format: `[{bar}] ETA: {eta}s | {value}/{total}`}); /* PRs which were found to be conflicting. */ @@ -103,7 +103,7 @@ export async function discoverNewConflictsForPr( const result = exec(`git rebase FETCH_HEAD`); if (result.code) { error('The requested PR currently has conflicts'); - cleanUpGitState(originalBranch); + cleanUpGitState(previousBranchOrRevision); process.exit(1); } @@ -130,7 +130,7 @@ export async function discoverNewConflictsForPr( info(); info(`Result:`); - cleanUpGitState(originalBranch); + cleanUpGitState(previousBranchOrRevision); // If no conflicts are found, exit successfully. if (conflicts.length === 0) { @@ -147,14 +147,14 @@ export async function discoverNewConflictsForPr( process.exit(1); } -/** Reset git back to the provided branch. */ -export function cleanUpGitState(branch: string) { +/** Reset git back to the provided branch or revision. */ +export function cleanUpGitState(previousBranchOrRevision: string) { // Ensure that any outstanding rebases are aborted. exec(`git rebase --abort`); // Ensure that any changes in the current repo state are cleared. exec(`git reset --hard`); // Checkout the original branch from before the run began. - exec(`git checkout ${branch}`); + exec(`git checkout ${previousBranchOrRevision}`); // Delete the generated branch. exec(`git branch -D ${tempWorkingBranch}`); } diff --git a/dev-infra/pr/merge/strategies/autosquash-merge.ts b/dev-infra/pr/merge/strategies/autosquash-merge.ts index 198eda3daf..e304ed98bd 100644 --- a/dev-infra/pr/merge/strategies/autosquash-merge.ts +++ b/dev-infra/pr/merge/strategies/autosquash-merge.ts @@ -59,7 +59,7 @@ export class AutosquashMergeStrategy extends MergeStrategy { // is desired, we set the `GIT_SEQUENCE_EDITOR` environment variable to `true` so that // the rebase seems interactive to Git, while it's not interactive to the user. // See: https://github.com/git/git/commit/891d4a0313edc03f7e2ecb96edec5d30dc182294. - const branchBeforeRebase = this.git.getCurrentBranch(); + const branchOrRevisionBeforeRebase = this.git.getCurrentBranchOrRevision(); const rebaseEnv = needsCommitMessageFixup ? undefined : {...process.env, GIT_SEQUENCE_EDITOR: 'true'}; this.git.run( @@ -69,9 +69,9 @@ export class AutosquashMergeStrategy extends MergeStrategy { // Update pull requests commits to reference the pull request. This matches what // Github does when pull requests are merged through the Web UI. The motivation is // that it should be easy to determine which pull request contained a given commit. - // **Note**: The filter-branch command relies on the working tree, so we want to make - // sure that we are on the initial branch where the merge script has been run. - this.git.run(['checkout', '-f', branchBeforeRebase]); + // Note: The filter-branch command relies on the working tree, so we want to make sure + // that we are on the initial branch or revision where the merge script has been invoked. + this.git.run(['checkout', '-f', branchOrRevisionBeforeRebase]); this.git.run( ['filter-branch', '-f', '--msg-filter', `${MSG_FILTER_SCRIPT} ${prNumber}`, revisionRange]); diff --git a/dev-infra/pr/merge/task.ts b/dev-infra/pr/merge/task.ts index e02815cbc0..5a17784738 100644 --- a/dev-infra/pr/merge/task.ts +++ b/dev-infra/pr/merge/task.ts @@ -87,14 +87,14 @@ export class PullRequestMergeTask { new GithubApiMergeStrategy(this.git, this.config.githubApiMerge) : new AutosquashMergeStrategy(this.git); - // Branch that is currently checked out so that we can switch back to it once - // the pull request has been merged. - let previousBranch: null|string = null; + // Branch or revision that is currently checked out so that we can switch back to + // it once the pull request has been merged. + let previousBranchOrRevision: null|string = null; // The following block runs Git commands as child processes. These Git commands can fail. // We want to capture these command errors and return an appropriate merge request status. try { - previousBranch = this.git.getCurrentBranch(); + previousBranchOrRevision = this.git.getCurrentBranchOrRevision(); // Run preparations for the merge (e.g. fetching branches). await strategy.prepare(pullRequest); @@ -107,7 +107,7 @@ export class PullRequestMergeTask { // Switch back to the previous branch. We need to do this before deleting the temporary // branches because we cannot delete branches which are currently checked out. - this.git.run(['checkout', '-f', previousBranch]); + this.git.run(['checkout', '-f', previousBranchOrRevision]); await strategy.cleanup(pullRequest); @@ -123,8 +123,8 @@ export class PullRequestMergeTask { } finally { // Always try to restore the branch if possible. We don't want to leave // the repository in a different state than before. - if (previousBranch !== null) { - this.git.runGraceful(['checkout', '-f', previousBranch]); + if (previousBranchOrRevision !== null) { + this.git.runGraceful(['checkout', '-f', previousBranchOrRevision]); } } } diff --git a/dev-infra/pr/rebase/index.ts b/dev-infra/pr/rebase/index.ts index 0b9fa9fe77..8c0af93324 100644 --- a/dev-infra/pr/rebase/index.ts +++ b/dev-infra/pr/rebase/index.ts @@ -50,10 +50,10 @@ export async function rebasePr( } /** - * The branch originally checked out before this method performs any Git - * operations that may change the working branch. + * The branch or revision originally checked out before this method performed + * any Git operations that may change the working branch. */ - const originalBranch = git.getCurrentBranch(); + const previousBranchOrRevision = git.getCurrentBranchOrRevision(); /* Get the PR information from Github. */ const pr = await getPr(PR_SCHEMA, prNumber, config.github); @@ -121,7 +121,7 @@ export async function rebasePr( info(); info(`To abort the rebase and return to the state of the repository before this command`); info(`run the following command:`); - info(` $ git rebase --abort && git reset --hard && git checkout ${originalBranch}`); + info(` $ git rebase --abort && git reset --hard && git checkout ${previousBranchOrRevision}`); process.exit(1); } else { info(`Cleaning up git state, and restoring previous state.`); @@ -137,7 +137,7 @@ export async function rebasePr( // Ensure that any changes in the current repo state are cleared. git.runGraceful(['reset', '--hard'], {stdio: 'ignore'}); // Checkout the original branch from before the run began. - git.runGraceful(['checkout', originalBranch], {stdio: 'ignore'}); + git.runGraceful(['checkout', previousBranchOrRevision], {stdio: 'ignore'}); } } diff --git a/dev-infra/utils/git/index.ts b/dev-infra/utils/git/index.ts index dbfb50c180..3a15b5a098 100644 --- a/dev-infra/utils/git/index.ts +++ b/dev-infra/utils/git/index.ts @@ -119,9 +119,16 @@ export class GitClient { return this.run(['branch', branchName, '--contains', sha]).stdout !== ''; } - /** Gets the currently checked out branch. */ - getCurrentBranch(): string { - return this.run(['rev-parse', '--abbrev-ref', 'HEAD']).stdout.trim(); + /** Gets the currently checked out branch or revision. */ + getCurrentBranchOrRevision(): string { + const branchName = this.run(['rev-parse', '--abbrev-ref', 'HEAD']).stdout.trim(); + // If no branch name could be resolved. i.e. `HEAD` has been returned, then Git + // is currently in a detached state. In those cases, we just want to return the + // currently checked out revision/SHA. + if (branchName === 'HEAD') { + return this.run(['rev-parse', 'HEAD']).stdout.trim(); + } + return branchName; } /** Gets whether the current Git repository has uncommitted changes. */