feat(workspace): add clone.branches to clone only the checked-out ref
KN
1d ago+618+618+012345678901234567890123456789-8-8-0123456789
What type of PR is this?
/kind api
What this PR does / why we need it:
Workspaces are cloned with git clone --depth 1 --no-single-branch, which downloads the tip of every branch. On repositories with many branches this can be most of a Task's startup time. On a repository with about 6,300 branches, a laptop clone took 122s and 818 MB with today's flags, against 40s and 293 MB with --single-branch.
This PR adds Workspace.spec.clone.branches:
spec:
repo: https://github.com/example/repo.git
ref: main
clone:
branches: Single # All (default) | Single
All, or omitting the field, keeps today's clone of every branch tip.Singleclones onlyspec.ref, or the remote's default branch whenspec.refis empty.originis set up to track only that ref, so a plaingit fetch origindoesn't pick up other branches. To use another branch, rungit remote set-branches --add origin <branch>, thengit fetch --depth 1 origin <branch>. The CRD description anddocs/reference.mdstate this.- The field has no effect when
spec.refis a full commit SHA, which already uses its owninit+fetchpath. - It applies to Task Jobs and WorkerPools.
The branch-setup init container, which runs when Task.spec.branch or Session.spec.initialBranch is set, now fetches the branch like this:
git fetch --depth 1 origin "+refs/heads/$KELOS_BRANCH:refs/remotes/origin/$KELOS_BRANCH"
--depth 1: a plaingit fetch origin <branch>into a single-branch shallow clone downloads that branch's entire history. On kelos-dev/kelos that was 1,426 commits against 1. InAllmode the tip is already present, so the change is unconditional.- Explicit destination: keeps
origin/<branch>present, as the all-branches clone does today, so agents that readorigin/<branch>keep working. - Tracking (
Singleonly):branch-setupfirst runsgit remote set-branches --add origin "$KELOS_BRANCH". Without it, origin's fetch refspec covers only the cloned ref. After an agent pushes its branch,origin/<branch>stays at the old commit andgit push -usets no upstream. With it, later fetches and pushes keeporigin/<branch>current.Allmode doesn't need it, so the line is only added forSingle.
Which issue(s) this PR is related to:
N/A
Special notes for your reviewer:
- Struct, not a bool. I chose
clone: { branches: All | Single }instead, so the default can change later without reinterpreting what users wrote. It also gives future clone settings a place to go (depth, filter, sparse paths; see #518) without new top-level fields. Onlybranchesis added here.Singlematches git's--single-branch, which is the term users will search for. merge --ff-onlybecamereset --hard FETCH_HEADfor the case where the Task branch already exists locally, which only happens when it is the cloned branch. After a--depth 1fetch, the old local tip is not an ancestor of the new shallow tip. So if the remote moves between clone and fetch,--ff-onlyfails and the init container fails, in both modes; I confirmed this with git locally. Resetting is safe becausebranch-setuponly runs on a freshly cloned repo: Task workspaces areemptyDir, and Session init re-clones until the workspace is marked initialized, then skipsbranch-setup.- Conversion. The field exists only in v1alpha2. Workspace conversion is plain JSON, so a v1alpha1 round-trip drops it, as it already drops
ghproxy. A dropped value falls back toAll, which is slower but correct. - e2e. kelos-dev/kelos has no non-main branch that is guaranteed to last, so the e2e test clones tag
v0.59.0withbranches: Singleand setsspec.branch: main. That makesbranch-setupfetch a branch that isn't in the clone. AsetupCommandprints the git state. The test checks that the repo is shallow,mainis checked out atorigin/main, only one remote branch exists, and origin's fetch refspecs includemain. I ran the same steps locally against GitHub and they passed. - Tests.
- Unit: exact clone arguments for
SingleandAll, a commit-SHA ref ignoring the field, the full fetch and reset lines in thebranch-setupscript, theset-branchesline present forSingleand absent forAlland commit refs, and WorkerPool clone arguments in both modes. - Integration: a Task with
branches: Single, plus a check that an unknown value is rejected. - The existing exact-argument assertions for the default are unchanged.
- Unit: exact clone arguments for
Does this PR introduce a user-facing change?
Workspaces accept `spec.clone.branches`. Set it to `Single` to clone only the checked-out ref instead of the tip of every branch, which speeds up Task startup on repositories with many branches. The default, `All`, keeps the current behavior.