Don't offer undo for a pushed commit whose upstream ref was deleted - #82
Merged
Conversation
Undo of the last commit is withheld once the commit is pushed, so it can't rewrite published history. That check (isUnpushed) asks whether the tip is an ancestor of the branch's upstream — but a configured upstream can be gone from the remote (a stale local branch still tracking a deleted/renamed remote branch, e.g. `master` after the remote renamed its default to `main`). git keeps reporting the upstream, so the ancestor probe errored on the missing ref and the failure was read as "unpushed", wrongly offering to undo an already-published commit. When the upstream ref no longer resolves, fall back to the no-upstream test — "contained in any remote-tracking branch" — which still finds the commit on the remote and correctly reports it as pushed. Also enforce the pushed-commit guard inside the undo mutation's recorded path (not just the snapshot that decides whether to show the affordance), so a stale renderer snapshot or the "Undo Last Action" menu command can't slip a pushed tip past the check. A reset stays exempt: undoing it moves HEAD forward to restore commits and can never rewrite remote history.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
GitGrove offered to undo the last commit even when that commit was already pushed — it should refuse, so it never rewrites published history.
Seen on the Avalonia repo: on
master(tip842937d, which is an ancestor oforigin/mainand lives on many remote branches, so it is very much pushed), GitGrove offered the undo.The pushed-commit protection does exist (
isUnpushed), but it has the same root cause as #81:masteris configured to trackorigin/master, andorigin/masterno longer exists on the remote (default renamed tomain). git still reports the configured upstream, so:The error was interpreted as "not an ancestor → unpushed", so the undo was offered for an already-published commit.
Fix
Detection — when the configured upstream ref no longer resolves, fall back to the no-upstream test (
branch -r --contains, i.e. "contained in any remote-tracking branch"). That finds842937donorigin/mainand correctly reports it as pushed. Verified against the real Avalonia repo:readUndoSnapshotnow returnsnull(no affordance).Defense in depth — enforce the pushed-commit guard inside the
undo()mutation's recorded path, not just the snapshot that decides whether to show the affordance. Previously the recorded path reset with no pushed check, so a stale renderer snapshot or the "Undo Last Action" menu command could slip a pushed tip past it. A reset stays exempt (undoing a reset moves HEAD forward to restore commits, and can't rewrite remote history) — matching the existing snapshot logic.Tests
Two new integration tests in
undo.test.ts:bun test(811 pass),typecheck, andlintall green.