Skip to content

Adopt equivalent server-rebased branches - #344

Open
skarim wants to merge 3 commits into
skarim/rebase-onto-amended-commitsfrom
skarim/sync-server-rebases
Open

Adopt equivalent server-rebased branches#344
skarim wants to merge 3 commits into
skarim/rebase-onto-amended-commitsfrom
skarim/sync-server-rebases

Conversation

@skarim

@skarim skarim commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

After a stack was rebased on GitHub, gh stack rebase and gh stack sync fetched the rewritten branch tips but would not adopt them because the local branches had diverged from their remote-tracking refs. The commands then tried to rebase or push the stale local branches, often failing even though the server-side rebase had completed successfully.

This change snapshots branch tips before fetching and adopts a server-side rewrite only when the local branch was unchanged, the remote stack is still properly ordered, and git range-diff confirms the same commits in the same order. If both sides changed, commits differ, or the history contains merges, the command stops instead of overwriting either side.

Both rebase and sync now update local branches and stack metadata directly when a safe equivalent server rewrite is detected.

Testing

  • go vet ./...
  • go test -race -count=1 ./...
  • Real-Git coverage for server-side rebase adoption through both rebase and sync
  • Coverage for local-only changes, concurrent rewrites, reordered or changed commits, merge commits, and rollback after a partial ref-update failure

Stack created with GitHub Stacks CLIGive Feedback 💬

Snapshot tracking refs before fetch so rebase and sync can distinguish remote rewrites from local work. Adopt only correctly stacked, same-order range-diff-equivalent commits, and stop safely when both sides changed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30bcbf2a-5ef1-4bdb-a0fc-618294ae8ded
Copilot AI review requested due to automatic review settings July 28, 2026 22:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds safe adoption of equivalent server-rebased stack branches.

Changes:

  • Snapshots branch tips and validates rewritten histories with git range-diff.
  • Integrates adoption into rebase and sync, including rollback handling.
  • Adds tests and user documentation.
Show a summary per file
File Description
cmd/utils.go Implements snapshotting and remote-tip adoption.
cmd/utils_test.go Tests adoption and rollback scenarios.
cmd/rebase.go Adopts remote rewrites during rebase.
cmd/rebase_test.go Adds end-to-end rebase and sync coverage.
cmd/sync.go Integrates adoption into synchronization.
internal/git/git.go Exposes range equivalence checking.
internal/git/gitops.go Implements git range-diff validation.
internal/git/gitops_test.go Tests equivalence, ordering, and merges.
internal/git/mock_ops.go Adds range-diff mock support.
README.md Documents adoption behavior.
docs/src/content/docs/reference/cli.md Updates CLI reference.
docs/src/content/docs/guides/ui.md Documents server-rebase workflow.
skills/gh-stack/SKILL.md Updates agent command guidance.

Review details

Comments suppressed due to low confidence (2)

cmd/utils.go:998

  • The earlier SHA comparison is not atomic with these destructive updates. Another Git process can advance a branch after it is checked at line 878, and ResetHard/branch -f will then overwrite that new local work even though the adoption path promises to stop when the local side changed. Update refs with an expected-old SHA (ideally as one ref transaction), and guard the checked-out branch before resetting its worktree.
		if update.branch == currentBranch {
			updateErr = git.ResetHard(update.remoteRef)
		} else {
			updateErr = git.UpdateBranchRef(update.branch, update.remoteSHA)
		}

cmd/utils.go:1005

  • Rollback failures are discarded here. If restoring an already-adopted branch fails, the command reports only the later update failure and leaves the stack partially rewritten without telling the user which ref needs recovery. Collect and include every rollback error in the returned error (or make the updates transactional).
				if previous.branch == currentBranch {
					_ = git.ResetHard(previous.localSHA)
				} else {
					_ = git.UpdateBranchRef(previous.branch, previous.localSHA)
  • Files reviewed: 13/13 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread cmd/utils.go Outdated
skarim added 2 commits July 28, 2026 18:46
Only require a clean worktree when adopting the checked-out branch with reset --hard. Non-current branch updates remain safe with unrelated working-tree changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 30bcbf2a-5ef1-4bdb-a0fc-618294ae8ded
Recover the previous remote tip from branch reflogs when an earlier fetch
already advanced the tracking ref. Adopt equivalent server rebases while
stopping sync before it overwrites non-equivalent remote commits, without
blocking local-only rewrites.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants