diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index de1b4847..e38b0a8e 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Git extension updates now handle force-pushed remotes gracefully instead of failing ([#961](https://github.com/badlogic/pi-mono/pull/961) by [@aliou](https://github.com/aliou)) + ## [0.50.0] - 2026-01-26 ### New Features @@ -66,7 +70,6 @@ There are multiple SDK breaking changes since v0.49.3. For the quickest migratio ### Fixed -- Git extension updates now handle force-pushed remotes gracefully instead of failing ([#961](https://github.com/badlogic/pi-mono/pull/961) by [@aliou](https://github.com/aliou)) - Extension `setWorkingMessage()` calls in `agent_start` handlers now work correctly; previously the message was silently ignored because the loading animation didn't exist yet ([#935](https://github.com/badlogic/pi-mono/issues/935)) - Fixed package auto-discovery to respect loader rules, config overrides, and force-exclude patterns - Fixed /reload restoring the correct editor after reload ([#949](https://github.com/badlogic/pi-mono/pull/949) by [@Perlence](https://github.com/Perlence)) diff --git a/packages/coding-agent/src/core/package-manager.ts b/packages/coding-agent/src/core/package-manager.ts index 6c156174..deef8702 100644 --- a/packages/coding-agent/src/core/package-manager.ts +++ b/packages/coding-agent/src/core/package-manager.ts @@ -939,9 +939,8 @@ export class DefaultPackageManager implements PackageManager { // Fetch latest from remote (handles force-push by getting new history) await this.runCommand("git", ["fetch", "--prune", "origin"], { cwd: targetDir }); - // Detect default branch and reset to it - const defaultBranch = this.getGitDefaultBranch(targetDir); - await this.runCommand("git", ["reset", "--hard", `origin/${defaultBranch}`], { cwd: targetDir }); + // Reset to upstream tracking branch (handles force-push gracefully) + await this.runCommand("git", ["reset", "--hard", "@{upstream}"], { cwd: targetDir }); // Clean untracked files (extensions should be pristine) await this.runCommand("git", ["clean", "-fdx"], { cwd: targetDir }); @@ -952,50 +951,6 @@ export class DefaultPackageManager implements PackageManager { } } - /** - * Detect the default branch of a git repository. - * Tries multiple methods with fallbacks. - */ - private getGitDefaultBranch(repoDir: string): string { - // Try symbolic-ref first (fast and reliable) - const symbolicRef = spawnSync("git", ["symbolic-ref", "-q", "refs/remotes/origin/HEAD"], { - cwd: repoDir, - encoding: "utf-8", - }); - if (symbolicRef.status === 0 && symbolicRef.stdout) { - // Returns something like "refs/remotes/origin/main" - const match = symbolicRef.stdout.trim().match(/refs\/remotes\/origin\/(.+)/); - if (match) { - return match[1]; - } - } - - // Try common branch names - for (const branch of ["main", "master"]) { - const showRef = spawnSync("git", ["show-ref", "--verify", `refs/remotes/origin/${branch}`], { - cwd: repoDir, - encoding: "utf-8", - }); - if (showRef.status === 0) { - return branch; - } - } - - // Last resort: use current branch - const revParse = spawnSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], { - cwd: repoDir, - encoding: "utf-8", - }); - if (revParse.status === 0 && revParse.stdout) { - const branch = revParse.stdout.trim(); - if (branch && branch !== "HEAD") { - return branch; - } - } - - return "main"; - } - private async removeGit(source: GitSource, scope: SourceScope): Promise { const targetDir = this.getGitInstallPath(source, scope); if (!existsSync(targetDir)) return;