fix(trail): require branch push to origin before creating a trail · Entire
fix(trail): require branch push to origin before creating a trail
dc40fb6→main· dipree·4w ago·2 files·+37 added/-18 removed
Make delivering the branch to origin a precondition for 'entire trail create'. Previously the push was gated on the CLI having created the branch locally, so 'git checkout -b foo && entire trail create --branch foo' bound the trail without ever pushing foo. The server then had no remote branch to anchor to and backfilled it at the base tip, producing local/remote/work drift while still printing 'Created trail'.
Now the branch is always pushed (hard-failing on auth/non-fast-forward errors) and the create request sends branch_action=link so the server attaches the delivered branch instead of backfilling at base.
Sessions
e0ad760f2e8eView transcript
Changes
2
cmd/entire/cli
api
Mtrail_types.go+16/-9
Mtrail_cmd.go+21/-9
// TrailCreateRequest is the body for POST /api/v1/trails/:host/:owner/:repo.
type TrailCreateRequest struct {
Title string `json:"title"`
Body string `json:"body,omitempty"`
BranchName string `json:"branch_name"`
Base string `json:"base,omitempty"`
Status string `json:"status,omitempty"`
Assignees []string `json:"assignees,omitempty"`
Labels []string `json:"labels,omitempty"`
Priority string `json:"priority,omitempty"`
Type string `json:"type,omitempty"`
// BranchAction tells the server how to bind BranchName. The CLI always
// pushes the branch to the remote before creating the trail, so it sends
// "link" to attach the already-delivered branch. This prevents the server
// from backfilling a backing branch at the base tip when the branch was
// never delivered (which would silently anchor the trail to empty/diverged
// content). Valid values: "create" (default, server-side) or "link".
BranchAction string `json:"branch_action,omitempty"`
}
Mcmd/entire/cli/api/trail_types.go+16/-9
641 unmodified lines
if needsCreation {
// needsCreation is a local-only signal, so the branch may still exist on
// origin (e.g. a teammate pushed it and we never fetched). In that case the
// remote branch is not ours, and our push may merely fast-forward it; we
// must not delete it during cleanup. Only treat the remote branch as
// created-by-us when it did not already exist before our push.
// Delivering the branch to origin is a PRECONDITION for trail creation, not
// an optional follow-up. A trail binds to a *remote* branch; if the branch
// never reaches origin the server has nothing to anchor to and backfills it
// at the base tip, producing a trail whose backing branch does not reflect
// the user's work (local branch, remote branch, and actual work all differ).
// We therefore always push and hard-fail on error, regardless of whether we
// created the branch locally. (Previously this was gated on needsCreation,
// so `git checkout -b foo && entire trail create --branch foo` created the
// trail without ever pushing foo.)
{
// branchExistsOnOrigin tells us whether origin already has this branch
// (e.g. a teammate pushed it, or we pushed it on a previous run). In that
// case our push may merely fast-forward it and we must not delete it
// during cleanup. Only treat the remote branch as created-by-us when it
// did not already exist before our push.
existedOnOrigin, existErr := branchExistsOnOrigin(branch)
if existErr != nil {
// Be conservative: if we cannot tell, do not delete the remote branch.
}
if err := pushBranchToOrigin(branch); err != nil {
cleanupCreatedTrailBranch(repo, branch, localBranchCreated, false, errW)
return fmt.Errorf("failed to push branch %q: %w", branch, err)
}
}
}
Mcmd/entire/cli/trail_cmd.go+21/-9