Skip to content

Commit f632712

Browse files
authored
Fix stale merged-PR rebase boundaries (#586)
* Fix stale merged-PR rebase boundaries Cache merged PR heads independently of local branch snapshots and compare fallback cutoffs by ancestry. Backfill existing stacks and preserve worktree recovery boundaries. * Fix rebase boundaries for recovery and regular merges Keep named trunk refs for legacy fork-point discovery and preserve recorded bases already integrated by regular merges.
1 parent c477b7d commit f632712

18 files changed

Lines changed: 1055 additions & 88 deletions

File tree

‎cmd/checkout.go‎

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -686,13 +686,8 @@ func importRemoteStack(
686686
branchRefs := make([]stack.BranchRef, len(prs))
687687
for i, pr := range prs {
688688
branchRefs[i] = stack.BranchRef{
689-
Branch: pr.HeadRefName,
690-
PullRequest: &stack.PullRequestRef{
691-
Number: pr.Number,
692-
ID: pr.ID,
693-
URL: pr.URL,
694-
Merged: pr.Merged,
695-
},
689+
Branch: pr.HeadRefName,
690+
PullRequest: pullRequestRef(pr, nil),
696691
}
697692
}
698693

@@ -728,12 +723,7 @@ func syncRemotePRState(s *stack.Stack, prs []*github.PullRequest) {
728723
if !ok {
729724
continue
730725
}
731-
s.Branches[i].PullRequest = &stack.PullRequestRef{
732-
Number: pr.Number,
733-
ID: pr.ID,
734-
URL: pr.URL,
735-
Merged: pr.Merged,
736-
}
726+
s.Branches[i].PullRequest = pullRequestRef(pr, s.Branches[i].PullRequest)
737727
s.Branches[i].Queued = pr.IsQueued()
738728
}
739729
}

‎cmd/checkout_test.go‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,7 @@ func TestCheckout_NumericTarget_MergedBranchDeletedFromRemote(t *testing.T) {
12391239
},
12401240
FindPRByNumberFn: func(number int) (*github.PullRequest, error) {
12411241
prs := map[int]*github.PullRequest{
1242-
10: {ID: "PR_10", Number: 10, HeadRefName: "feat-1", BaseRefName: "main", Merged: true, State: "MERGED", URL: "https://github.com/o/r/pull/10"},
1242+
10: {ID: "PR_10", Number: 10, HeadRefName: "feat-1", HeadRefOID: "merged-head", BaseRefName: "main", Merged: true, State: "MERGED", URL: "https://github.com/o/r/pull/10"},
12431243
11: {ID: "PR_11", Number: 11, HeadRefName: "feat-2", BaseRefName: "feat-1", State: "OPEN", URL: "https://github.com/o/r/pull/11"},
12441244
}
12451245
return prs[number], nil
@@ -1253,6 +1253,24 @@ func TestCheckout_NumericTarget_MergedBranchDeletedFromRemote(t *testing.T) {
12531253
assert.Equal(t, "feat-2", checkedOut)
12541254
assert.Contains(t, output, "Skipping merged branch feat-1")
12551255
assert.Contains(t, output, "Imported stack with 2 branches")
1256+
sf, err := stack.Load(gitDir)
1257+
require.NoError(t, err)
1258+
assert.Equal(t, "merged-head", sf.Stacks[0].Branches[0].PullRequest.MergedHead)
1259+
assert.Empty(t, sf.Stacks[0].Branches[0].Head)
1260+
}
1261+
1262+
func TestSyncRemotePRState_MergedHead(t *testing.T) {
1263+
s := &stack.Stack{Branches: []stack.BranchRef{{
1264+
Branch: "parent", Head: "local",
1265+
PullRequest: &stack.PullRequestRef{Number: 10, Merged: true, MergedHead: "cached"},
1266+
}}}
1267+
syncRemotePRState(s, []*github.PullRequest{{Number: 10, HeadRefName: "parent", Merged: true}})
1268+
assert.Equal(t, "cached", s.Branches[0].PullRequest.MergedHead)
1269+
assert.Equal(t, "local", s.Branches[0].Head)
1270+
1271+
syncRemotePRState(s, []*github.PullRequest{{Number: 11, HeadRefName: "parent", State: "OPEN"}})
1272+
assert.Empty(t, s.Branches[0].PullRequest.MergedHead)
1273+
assert.False(t, s.Branches[0].IsMerged())
12561274
}
12571275

12581276
func TestCheckout_NumericTarget_AllPRsMerged(t *testing.T) {

‎cmd/rebase.go‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -250,10 +250,8 @@ func runRebase(cfg *config.Config, opts *rebaseOptions) error {
250250
if startIdx > 0 {
251251
prev := s.Branches[startIdx-1]
252252
if prev.IsMerged() {
253-
if sha, ok := originalRefs[prev.Branch]; ok {
254-
needsOnto = true
255-
ontoOldBase = sha
256-
}
253+
needsOnto = true
254+
ontoOldBase = originalRefs[prev.Branch]
257255
}
258256
}
259257

@@ -456,7 +454,8 @@ func continueRebase(cfg *config.Config, gitDir string) error {
456454
NeedsOnto: state.UseOnto,
457455
OntoOldBase: state.OntoOldBase,
458456
CommitterDateIsAuthorDate: state.CommitterDateIsAuthorDate,
459-
TrunkRef: trunkBase,
457+
TrunkRef: trunkRef,
458+
TrunkSHA: state.TrunkSHA,
460459
})
461460

462461
if result.Err != nil {

0 commit comments

Comments
 (0)