Skip to content

Commit b63aa16

Browse files
committed
backfill ontoOldBase for deleted merged branches
1 parent dcbed25 commit b63aa16

4 files changed

Lines changed: 37 additions & 5 deletions

File tree

cmd/rebase.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,17 @@ func runRebase(cfg *config.Config, opts *rebaseOptions) error {
188188
return ErrSilent
189189
}
190190

191+
// Backfill originalRefs for merged branches that were deleted locally.
192+
// The rebase loop uses originalRefs[br.Branch] as ontoOldBase; without
193+
// a valid entry the subsequent --onto rebase would receive an empty ref.
194+
for _, b := range s.Branches {
195+
if b.IsMerged() && !git.BranchExists(b.Branch) {
196+
if b.Head != "" {
197+
originalRefs[b.Branch] = b.Head
198+
}
199+
}
200+
}
201+
191202
// Track --onto rebase state for merged branches.
192203
needsOnto := false
193204
var ontoOldBase string

cmd/rebase_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,11 +1044,12 @@ func TestRebase_BranchDiverged_NoFF(t *testing.T) {
10441044

10451045
func TestRebase_SkipsMergedBranchesNotExistingLocally(t *testing.T) {
10461046
// Simulates a stack where b1 is merged and its branch was auto-deleted
1047-
// from the remote, so it doesn't exist locally.
1047+
// from the remote, so it doesn't exist locally. The stored Head SHA is
1048+
// used as ontoOldBase for the next branch's --onto rebase.
10481049
s := stack.Stack{
10491050
Trunk: stack.BranchRef{Branch: "main"},
10501051
Branches: []stack.BranchRef{
1051-
{Branch: "b1", PullRequest: &stack.PullRequestRef{Number: 42, Merged: true}},
1052+
{Branch: "b1", Head: "b1-stored-head-sha", PullRequest: &stack.PullRequestRef{Number: 42, Merged: true}},
10521053
{Branch: "b2"},
10531054
},
10541055
}
@@ -1095,7 +1096,10 @@ func TestRebase_SkipsMergedBranchesNotExistingLocally(t *testing.T) {
10951096
assert.NoError(t, err)
10961097
assert.Contains(t, output, "Skipping b1")
10971098

1098-
// Only b2 should be rebased
1099+
// Only b2 should be rebased, and the rebase should use b1's stored
1100+
// Head SHA as oldBase so `git rebase --onto` receives valid arguments.
10991101
require.Len(t, rebaseCalls, 1)
11001102
assert.Equal(t, "b2", rebaseCalls[0].branch)
1103+
assert.Equal(t, "main", rebaseCalls[0].newBase)
1104+
assert.Equal(t, "b1-stored-head-sha", rebaseCalls[0].oldBase)
11011105
}

cmd/sync.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,20 @@ func runSync(cfg *config.Config, opts *syncOptions) error {
142142
}
143143
originalRefs, _ := git.RevParseMap(branchNames)
144144

145+
// Backfill originalRefs for merged branches that were deleted locally.
146+
// The rebase loop uses originalRefs[br.Branch] as ontoOldBase; without
147+
// a valid entry the subsequent --onto rebase would receive an empty ref.
148+
for _, b := range s.Branches {
149+
if b.IsMerged() && !git.BranchExists(b.Branch) {
150+
if b.Head != "" {
151+
if originalRefs == nil {
152+
originalRefs = make(map[string]string)
153+
}
154+
originalRefs[b.Branch] = b.Head
155+
}
156+
}
157+
}
158+
145159
needsOnto := false
146160
var ontoOldBase string
147161

cmd/sync_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ func TestSync_MergedBranchDeletedFromRemote(t *testing.T) {
848848
s := stack.Stack{
849849
Trunk: stack.BranchRef{Branch: "main"},
850850
Branches: []stack.BranchRef{
851-
{Branch: "b1", PullRequest: &stack.PullRequestRef{Number: 1, Merged: true}},
851+
{Branch: "b1", Head: "b1-stored-head-sha", PullRequest: &stack.PullRequestRef{Number: 1, Merged: true}},
852852
{Branch: "b2"},
853853
},
854854
}
@@ -915,7 +915,10 @@ func TestSync_MergedBranchDeletedFromRemote(t *testing.T) {
915915
assert.NoError(t, err)
916916
assert.Contains(t, output, "Skipping b1")
917917

918-
// Only b2 should be rebased
918+
// Only b2 should be rebased, and the rebase should use b1's stored
919+
// Head SHA as oldBase so `git rebase --onto` receives valid arguments.
919920
require.Len(t, rebaseOntoCalls, 1)
920921
assert.Equal(t, "b2", rebaseOntoCalls[0].branch)
922+
assert.Equal(t, "main", rebaseOntoCalls[0].newBase)
923+
assert.Equal(t, "b1-stored-head-sha", rebaseOntoCalls[0].oldBase)
921924
}

0 commit comments

Comments
 (0)