feat(workspace): add clone.branches to clone only the checked-out ref

KN
1d ago
+618-8

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.
  • Single clones only spec.ref, or the remote's default branch when spec.ref is empty. origin is set up to track only that ref, so a plain git fetch origin doesn't pick up other branches. To use another branch, run git remote set-branches --add origin <branch>, then git fetch --depth 1 origin <branch>. The CRD description and docs/reference.md state this.
  • The field has no effect when spec.ref is a full commit SHA, which already uses its own init + fetch path.
  • 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 plain git 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. In All mode 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 read origin/<branch> keep working.
  • Tracking (Single only): branch-setup first runs git 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 and git push -u sets no upstream. With it, later fetches and pushes keep origin/<branch> current. All mode doesn't need it, so the line is only added for Single.

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. Only branches is added here. Single matches git's --single-branch, which is the term users will search for.
  • merge --ff-only became reset --hard FETCH_HEAD for the case where the Task branch already exists locally, which only happens when it is the cloned branch. After a --depth 1 fetch, the old local tip is not an ancestor of the new shallow tip. So if the remote moves between clone and fetch, --ff-only fails and the init container fails, in both modes; I confirmed this with git locally. Resetting is safe because branch-setup only runs on a freshly cloned repo: Task workspaces are emptyDir, and Session init re-clones until the workspace is marked initialized, then skips branch-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 to All, 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.0 with branches: Single and sets spec.branch: main. That makes branch-setup fetch a branch that isn't in the clone. A setupCommand prints the git state. The test checks that the repo is shallow, main is checked out at origin/main, only one remote branch exists, and origin's fetch refspecs include main. I ran the same steps locally against GitHub and they passed.
  • Tests.
    • Unit: exact clone arguments for Single and All, a commit-SHA ref ignoring the field, the full fetch and reset lines in the branch-setup script, the set-branches line present for Single and absent for All and 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.

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.