Files
git-repo/docs/fetch-cmd.md
T
Gavin Mak a468ea7752 sync: implement reprojectcmd for the local half
Add `repo.reprojectcmd`, the checkout counterpart to `repo.fetchcmd`.
When set, `repo sync` runs this command instead of Git to materialize a
project's index and worktree at the target tree, while `repo` handles
ref updates directly via `git update-ref`.

This replaces Git's tree materialization steps: detaching HEAD,
fast-forwarding, and hard-resetting. Rebasing is not delegated, and the
command is skipped if HEAD is already at the target, if HEAD is ahead of
the target during fast-forward, or for MetaProjects.

The command runs in a subshell with project environment variables (such
as `REPO_TREV`). Before running, `repo` ensures no operation is in
progress and no staged changes exist. Worktree collision detection is
delegated to the command (preserving benign unstaged/untracked edits).
Afterward, `repo` verifies that HEAD was untouched and that the index
matches the target tree.

Like `repo.fetchcmd`, this requires `repo.uselocalgitdirs`. Nested
projects and submodules are unsupported; `repo sync` fails if the
manifest contains any while `repo.reprojectcmd` is enabled.

Verified end-to-end with repo init using local-gitdirs, repo.fetchcmd,
and repo.reprojectcmd ('git -C $REPO_PATH read-tree -m -u $REPO_TREV'):
  * Verified detached HEAD checkout and correct reflog generation across
    projects.
  * Verified benign unstaged edits and untracked files survive checkout.
  * Verified conflicting untracked files fail with exit 128 without
    clobbering worktree.
  * Verified staged changes fail upfront before reprojectcmd is executed.

Bug: 513329573
Change-Id: I964d24d22dccffc05a9b991ad69f3a7e93268c01
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/626281
Tested-by: Gavin Mak <gavinmak@google.com>
Reviewed-by: Brian Gan <brgan@google.com>
Commit-Queue: Gavin Mak <gavinmak@google.com>
2026-09-15 12:53:01 -07:00

2.4 KiB

Fetch Command Contract

The repo.fetchcmd configuration allows specifying a custom command to be executed during repo sync to fetch objects, instead of using standard git fetch. This is particularly useful in environments with virtualized filesystems or lazy checkouts where fetching metadata and downloading file contents should be decoupled.

The checkout half of a sync has a counterpart, repo.reprojectcmd; see docs/reproject-cmd.md.

Configuration

To use this feature, set the following in .repo/manifests.git/config:

[repo]
	fetchcmd = "your custom command here"
	uselocalgitdirs = true

Setting repo.fetchcmd requires repo.uselocalgitdirs to be set to true.

Environment Variables

The custom command is executed in a subshell populated with standard project-context environment variables. For details on standard variables (such as REPO_PROJECT, REPO_PATH, REPO_PROJECT_FETCH_URL, etc.), see the Environment section in repo help forall or subcmds/forall.py.

The following environment variable is specific to repo.fetchcmd:

  • REPO_TREV: The target revision resolved to a full commit hash.

Contract

Postconditions on exit 0

After the fetch command exits with status 0, repo expects the following postconditions to be met:

  1. git cat-file -e REPO_TREV succeeds (the commit must exist in the object store).
  2. The mapped local tracking ref (e.g. refs/remotes/REPO_REMOTE/<branch> for a branch revision, or the tag ref itself for a tag) must point to REPO_TREV.
  3. FETCH_HEAD must point to REPO_TREV.
  4. The commit graph from REPO_TREV must be reachable far enough to compute merge bases with local branches.

Invariants

  • The command should be idempotent; fetching the same REPO_TREV twice should be a no-op.
  • Only FETCH_HEAD and refs/remotes/* should be modified to preserve repo sync --network-only semantics. HEAD and local branches must not be touched by the fetch command.
  • Dirty worktree state must be preserved.
  • The command is not executed for MetaProjects (i.e. the internal repo repository itself at .repo/repo and the manifests repository at .repo/manifests).

Failure

  • A non-zero exit status aborts the project's sync, and the command's stderr is surfaced to the user.
  • repo verifies the tracking ref and target reachability after exit 0. Any mismatch is treated as a failure.