fix(trail): fetch existing remote branch before create · Entire

fix(trail): fetch existing remote branch before create

1fd4f9f→main·

dipree·4w ago·1 file·+35 added/-11 removed

Address PR review feedback:

Sessions

b73b63b3e546View transcript

[?
Fix Trail Creation Branch Handling and ValidationPi·Opus 4.8·1 step](/content/gh/entireio/cli/session/019ed956-c81a-74d1-9437-9fb289e1410f#timeline-b73b63b3e546/index.html)

Changes

1

634 unmodified lines

635
636
637
638
639
640
641
642
643
644
645
646
639
640
647
648
649
650
651
652
653
654
655
656
657
658
659
642
643
660
661
662
2 unmodified lines

665
666
667
652
653
654
655
656
657
668
669
660
670
671
672
673
732 unmodified lines

1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425

634 unmodified lines

localBranchCreated := false
    var remoteBranchPushed bool

// Don't delete a remote branch we didn't create during cleanup.
    existedOnOrigin, existErr := branchExistsOnOrigin(branch)
    if existErr != nil {
        fmt.Fprintf(errW, "Warning: could not check whether branch %s already exists on origin: %v\n", branch, existErr)
        existedOnOrigin = true
    }

if needsCreation {
        if err := createBranch(repo, branch); err != nil {
            return fmt.Errorf("failed to create branch %q: %w", branch, err)
        }
        if existedOnOrigin {
            if err := fetchBranchFromOrigin(branch); err != nil {
                return fmt.Errorf("failed to fetch branch %q from origin: %w", branch, err)
            }
            localBranchCreated = true
            fmt.Fprintf(w, "Fetched branch %s from origin\n", branch)
        } else {
            if err := createBranch(repo, branch); err != nil {
                return fmt.Errorf("failed to create branch %q: %w", branch, err)
            }
            localBranchCreated = true
            fmt.Fprintf(w, "Created branch %s\n", branch)
        }
        localBranchCreated = true
        fmt.Fprintf(w, "Created branch %s\n", branch)
    } else if currentBranch != branch {
        fmt.Fprintf(w, "Note: trail will be created for branch %q (not the current branch)\n", branch)
    }
2 unmodified lines

// deliver it before creating the trail rather than letting the server
    // backfill it at the base tip.
    {
        // Don't delete a remote branch we didn't create during cleanup.
        existedOnOrigin, existErr := branchExistsOnOrigin(branch)
        if existErr != nil {
            fmt.Fprintf(errW, "Warning: could not check whether branch %s already exists on origin: %v\n", branch, existErr)
            existedOnOrigin = true
        }
        if err := pushBranchToOrigin(branch); err != nil {
            cleanupCreatedTrailBranch(repo, branch, localBranchCreated, false, errW)
            return fmt.Errorf("failed to push branch %q to origin: %w\nhint: the trail was not created because its branch could not be delivered to the remote.\n  - if this is an auth error, link your GitHub account and retry\n  - if this is a non-fast-forward, update your base (git fetch && git rebase) and retry", branch, err)
        }
        remoteBranchPushed = !existedOnOrigin
        fmt.Fprintf(w, "Pushed branch %s to origin\n", branch)
732 unmodified lines

}
}

func fetchBranchFromOrigin(branchName string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
    defer cancel()
    if err := ValidateBranchName(ctx, branchName); err != nil {
        return err
    }
    refspec := fmt.Sprintf("refs/heads/%%s:refs/heads/%%s", branchName, branchName)
    cmd := exec.CommandContext(ctx, "git", "fetch", "--no-tags", "origin", refspec)
    if output, err := cmd.CombinedOutput(); err != nil {
        return fmt.Errorf("%s: %w", strings.TrimSpace(string(output)), err)
    }
    return nil
}

// pushBranchToOrigin pushes a branch to the origin remote.
func pushBranchToOrigin(branchName string) error {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)