Skip to content

Commit 0a472a3

Browse files
authored
repo sync: Fix deleting wrong tracking branch for renamed branches (#401)
If a branch is renamed after submission and then merged, the tracking branch name does not match the local branch name. This case must be correctly handled when deleting the tracking branch: if we know the upstream branch name use `$remote/$upstreamBranch` instead of `$remote/$branch`. Also drop the outdated comment about how we detect merged branches sinc we're indeed doing both (1) and (2) now.
1 parent 0f9d7e7 commit 0a472a3

File tree

3 files changed

+88
-22
lines changed

3 files changed

+88
-22
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: Fixed
2+
body: 'repo sync: Delete the correct tracking branch for renamed branches.'
3+
time: 2024-09-14T12:03:58.254791-07:00

repo_sync.go

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -204,19 +204,6 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
204204
remoteRepo forge.Repository,
205205
opts *globalOptions,
206206
) error {
207-
// There are two options for detecting merged branches:
208-
//
209-
// 1. Query the CR status for each submitted branch.
210-
// This is more accurate, but requires a lot of API calls.
211-
// 2. List recently merged PRs and match against tracked branches.
212-
// The number of API calls here is smaller,
213-
// but the matching is less accurate because the CR may have been
214-
// submitted by someone else.
215-
//
216-
// For now, we'll go for (1) with the assumption that the number of
217-
// submitted branches is small enough that we can afford the API calls.
218-
// In the future, we may need a hybrid approach that switches to (2).
219-
220207
knownBranches, err := svc.LoadBranches(ctx)
221208
if err != nil {
222209
return fmt.Errorf("list tracked branches: %w", err)
@@ -226,6 +213,9 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
226213
Name string
227214
Change forge.ChangeID
228215
Merged bool
216+
217+
// Branch name pushed to the remote.
218+
UpstreamBranch string
229219
}
230220

231221
type trackedBranch struct {
@@ -235,6 +225,9 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
235225
Merged bool
236226
RemoteHeadSHA git.Hash
237227
LocalHeadSHA git.Hash
228+
229+
// Branch name pushed to the remote.
230+
UpstreamBranch string
238231
}
239232

240233
// There are two kinds of branches under consideration:
@@ -254,18 +247,27 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
254247
trackedBranches []*trackedBranch
255248
)
256249
for _, b := range knownBranches {
250+
upstreamBranch := b.UpstreamBranch
251+
if upstreamBranch == "" {
252+
upstreamBranch = b.Name
253+
}
254+
257255
if b.Change != nil {
258256
b := &submittedBranch{
259-
Name: b.Name,
260-
Change: b.Change.ChangeID(),
257+
Name: b.Name,
258+
Change: b.Change.ChangeID(),
259+
UpstreamBranch: upstreamBranch,
261260
}
262261
submittedBranches = append(submittedBranches, b)
263262
} else {
264263
// TODO:
265264
// Filter down to only branches that have
266265
// a remote tracking branch:
267266
// either $remote/$UpstreamBranch or $remote/$branch exists.
268-
b := &trackedBranch{Name: b.Name}
267+
b := &trackedBranch{
268+
Name: b.Name,
269+
UpstreamBranch: upstreamBranch,
270+
}
269271
trackedBranches = append(trackedBranches, b)
270272
}
271273
}
@@ -338,14 +340,22 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
338340
}
339341
wg.Wait()
340342

341-
var branchesToDelete []string
343+
type branchDeletion struct {
344+
BranchName string
345+
UpstreamName string
346+
}
347+
348+
var branchesToDelete []branchDeletion
342349
for _, branch := range submittedBranches {
343350
if !branch.Merged {
344351
continue
345352
}
346353

347354
log.Infof("%v: %v was merged", branch.Name, branch.Change)
348-
branchesToDelete = append(branchesToDelete, branch.Name)
355+
branchesToDelete = append(branchesToDelete, branchDeletion{
356+
BranchName: branch.Name,
357+
UpstreamName: branch.UpstreamBranch,
358+
})
349359
}
350360

351361
for _, branch := range trackedBranches {
@@ -355,7 +365,10 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
355365

356366
if branch.RemoteHeadSHA == branch.LocalHeadSHA {
357367
log.Infof("%v: %v was merged", branch.Name, branch.Change)
358-
branchesToDelete = append(branchesToDelete, branch.Name)
368+
branchesToDelete = append(branchesToDelete, branchDeletion{
369+
BranchName: branch.Name,
370+
UpstreamName: branch.UpstreamBranch,
371+
})
359372
continue
360373
}
361374

@@ -381,7 +394,10 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
381394
}
382395

383396
if shouldDelete {
384-
branchesToDelete = append(branchesToDelete, branch.Name)
397+
branchesToDelete = append(branchesToDelete, branchDeletion{
398+
BranchName: branch.Name,
399+
UpstreamName: branch.UpstreamBranch,
400+
})
385401
}
386402
}
387403

@@ -390,7 +406,7 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
390406
// (e.g. from the bottom of the stack up)
391407
for _, branch := range branchesToDelete {
392408
err := (&branchDeleteCmd{
393-
Branch: branch,
409+
Branch: branch.BranchName,
394410
Force: true,
395411
}).Run(ctx, log, opts)
396412
if err != nil {
@@ -399,7 +415,7 @@ func (cmd *repoSyncCmd) deleteMergedBranches(
399415

400416
// Also delete the remote tracking branch for this branch
401417
// if it still exists.
402-
remoteBranch := remote + "/" + branch
418+
remoteBranch := remote + "/" + branch.UpstreamName
403419
if _, err := repo.PeelToCommit(ctx, remoteBranch); err == nil {
404420
if err := repo.DeleteBranch(ctx, remoteBranch, git.BranchDeleteOptions{
405421
Remote: true,
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# If a branch is renamed after being submitted, and then merged,
2+
# repo sync should still delete the correct tracking branch.
3+
4+
as 'Test <[email protected]>'
5+
at '2024-09-14T12:05:06Z'
6+
7+
# setup
8+
cd repo
9+
git init
10+
git commit --allow-empty -m 'Initial commit'
11+
12+
# set up a fake GitHub remote
13+
shamhub init
14+
shamhub new origin alice/example.git
15+
shamhub register alice
16+
git push origin main
17+
18+
env SHAMHUB_USERNAME=alice
19+
gs auth login
20+
21+
# create a new branch and submit it
22+
git add feature1.txt
23+
gs bc -m 'Add feature1' feature1
24+
gs branch submit --fill
25+
stderr 'Created #'
26+
27+
# rename and re-submit
28+
gs branch rename feat1
29+
cp $WORK/extra/feature1-update.txt feature1.txt
30+
git add feature1.txt
31+
git commit -m 'update feature1'
32+
33+
# merge the PR
34+
shamhub merge alice/example 1
35+
36+
gs repo sync
37+
stderr 'feat1: deleted'
38+
39+
# tracking branch must have been deleted
40+
! git rev-parse --verify origin/feature1
41+
42+
-- repo/feature1.txt --
43+
Contents of feature1
44+
45+
-- extra/feature1-update.txt --
46+
New contents of feature1
47+

0 commit comments

Comments
 (0)