Skip to content

Commit a3320a8

Browse files
Copilotalexr00
andcommitted
Detect and handle force-pushed branches in pull notification
Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent 0b3e759 commit a3320a8

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/github/folderRepositoryManager.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2492,6 +2492,61 @@ export class FolderRepositoryManager extends Disposable {
24922492

24932493
private async pullBranch(branch: Branch) {
24942494
if (this._repository.state.HEAD?.name === branch.name) {
2495+
// Check if the branch has diverged (ahead > 0 && behind > 0)
2496+
// This typically happens when the remote has been force-pushed or rebased
2497+
if (branch.ahead !== undefined && branch.ahead > 0 && branch.behind !== undefined && branch.behind > 0) {
2498+
const resetToRemote = vscode.l10n.t('Reset to Remote');
2499+
const cancel = vscode.l10n.t('Cancel');
2500+
const result = await vscode.window.showWarningMessage(
2501+
vscode.l10n.t('The pull request branch has diverged from the remote (you have {0} local commit(s), remote has {1} new commit(s)).\n\nThis usually happens when the remote branch has been force-pushed or rebased. You can reset your local branch to match the remote (this will discard your {0} local commit(s)), or cancel and resolve manually.', branch.ahead, branch.behind),
2502+
{ modal: true },
2503+
resetToRemote,
2504+
cancel
2505+
);
2506+
2507+
if (result === resetToRemote) {
2508+
try {
2509+
if (branch.upstream) {
2510+
// Fetch to ensure we have the latest remote state
2511+
await this._repository.fetch(branch.upstream.remote, branch.name);
2512+
2513+
// Get the remote branch reference
2514+
const remoteBranchRef = `refs/remotes/${branch.upstream.remote}/${branch.upstream.name}`;
2515+
const remoteBranch = await this._repository.getBranch(remoteBranchRef);
2516+
const currentBranchName = branch.name!;
2517+
2518+
// Create a temp branch at the remote commit
2519+
const tempBranchName = `temp-pr-update-${Date.now()}`;
2520+
await this._repository.createBranch(tempBranchName, false, remoteBranch.commit);
2521+
await this._repository.setBranchUpstream(tempBranchName, remoteBranchRef);
2522+
2523+
// Checkout the temp branch
2524+
await this._repository.checkout(tempBranchName);
2525+
2526+
// Delete the old branch (force delete since it has un-merged commits)
2527+
await this._repository.deleteBranch(currentBranchName, true);
2528+
2529+
// Recreate the original branch at the same commit
2530+
await this._repository.createBranch(currentBranchName, false, remoteBranch.commit);
2531+
await this._repository.setBranchUpstream(currentBranchName, remoteBranchRef);
2532+
2533+
// Checkout the recreated branch
2534+
await this._repository.checkout(currentBranchName);
2535+
2536+
// Delete the temp branch
2537+
await this._repository.deleteBranch(tempBranchName, true);
2538+
2539+
Logger.appendLine(`Successfully reset branch ${currentBranchName} to remote ${remoteBranchRef}`, this.id);
2540+
}
2541+
} catch (e) {
2542+
Logger.error(`Error resetting branch to remote: ${e}`, this.id);
2543+
vscode.window.showErrorMessage(vscode.l10n.t('Failed to reset branch to remote: {0}', e.message || e));
2544+
}
2545+
}
2546+
// If cancel, do nothing
2547+
return;
2548+
}
2549+
24952550
await this._repository.pull();
24962551
}
24972552
}

0 commit comments

Comments
 (0)