Skip to content

Commit 97ccc62

Browse files
Copilotalexr00
andcommitted
Use merge-base analysis to detect force-push vs normal divergence
Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent 9911a0a commit 97ccc62

File tree

1 file changed

+29
-2
lines changed

1 file changed

+29
-2
lines changed

src/github/folderRepositoryManager.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2493,12 +2493,39 @@ export class FolderRepositoryManager extends Disposable {
24932493
private async pullBranch(branch: Branch) {
24942494
if (this._repository.state.HEAD?.name === branch.name) {
24952495
// Check if the branch has diverged (ahead > 0 && behind > 0)
2496-
// This typically happens when the remote has been force-pushed or rebased
24972496
if (branch.ahead !== undefined && branch.ahead > 0 && branch.behind !== undefined && branch.behind > 0) {
2497+
// Use merge-base analysis to distinguish between force-push and normal divergence
2498+
// If remote was force-pushed, the merge-base will be at or near the current HEAD
2499+
// If it's normal divergence, the merge-base will be older than both HEAD and remote
2500+
let isForcePush = false;
2501+
2502+
if (branch.upstream && branch.commit) {
2503+
try {
2504+
const remoteBranchRef = `${branch.upstream.remote}/${branch.upstream.name}`;
2505+
const mergeBase = await this._repository.getMergeBase(branch.commit, remoteBranchRef);
2506+
2507+
// If merge-base equals the current HEAD commit, it means the remote history
2508+
// was rewritten (force-push/rebase), and local commits don't exist in remote
2509+
if (mergeBase === branch.commit) {
2510+
isForcePush = true;
2511+
}
2512+
} catch (e) {
2513+
// If we can't determine merge-base, fall back to treating it as normal divergence
2514+
Logger.debug(`Could not determine merge-base: ${e}`, this.id);
2515+
}
2516+
}
2517+
2518+
// Only show the reset dialog for force-push scenarios
2519+
if (!isForcePush) {
2520+
// Normal divergence - let the default pull behavior handle it
2521+
await this._repository.pull();
2522+
return;
2523+
}
2524+
24982525
const resetToRemote = vscode.l10n.t('Reset to Remote');
24992526
const cancel = vscode.l10n.t('Cancel');
25002527
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 local changes), or cancel and resolve manually.', branch.ahead, branch.behind),
2528+
vscode.l10n.t('The remote branch has been force-pushed or rebased. Your local branch has {0} commit(s) that no longer exist in the remote history.\n\nYou can reset your local branch to match the remote (this will discard your local commits), or cancel and resolve manually.', branch.ahead),
25022529
{ modal: true },
25032530
resetToRemote,
25042531
cancel

0 commit comments

Comments
 (0)