When a project's revision is an unpinned branch or tag and superprojects are not used (so self.revisionId is unset), _CustomFetch previously ran git ls-remote against the Git remote before invoking repo.fetchcmd just to pre-populate REPO_TREV. This added a per-project network round-trip before fetchcmd and forced branch resolution against the Git remote rather than letting fetchcmd resolve REPO_RREV from its own server (just as standard git fetch does in _RemoteFetch). Only populate REPO_TREV before fetchcmd when the target commit SHA is already known (via self.revisionId from superproject or a SHA-pinned revisionExpr). When REPO_RREV is an unpinned branch or tag, leave REPO_TREV empty, let fetchcmd resolve REPO_RREV and update the local tracking ref and FETCH_HEAD, and verify afterward that the tracking ref and FETCH_HEAD resolve to the same valid commit in the object store. Bug: 543101585 Change-Id: I482bf4c022d0e669e5620d4517581ac193983da0 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/640423 Reviewed-by: Brian Gan <brgan@google.com> Commit-Queue: Gavin Mak <gavinmak@google.com> Tested-by: Gavin Mak <gavinmak@google.com>
2.8 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 commit hash when the revision is already pinned to a commit (e.g. via a superproject or a commit SHA in the manifest), or empty whenREPO_RREVis an unpinned branch or tag to be resolved by the fetch command.
Contract
Postconditions on exit 0
After the fetch command exits with status 0, repo expects the following
postconditions to be met:
- When the manifest revision names a branch or tag, the mapped local tracking
ref (e.g.
refs/remotes/REPO_REMOTE/<branch>for a branch, orrefs/tags/<tag>for a tag) must resolve to a valid commit in the object store (git rev-parse --verify <ref>^{commit}), and must equalREPO_TREVifREPO_TREVwas non-empty. FETCH_HEADmust resolve to the same target commit in the object store (git rev-parse --verify FETCH_HEAD^{commit}).- The commit graph from the target commit must be reachable far enough to compute merge bases with local branches.
Invariants
- The command should be idempotent; repeating the same fetch should be a no-op.
- Only
FETCH_HEAD,refs/remotes/*, andrefs/tags/*should be modified to preserverepo sync --network-onlysemantics.HEADand 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 internalreporepository itself at.repo/repoand themanifestsrepository at.repo/manifests).
Failure
- A non-zero exit status aborts the project's sync, and the command's stderr is surfaced to the user.
repoverifies the tracking ref and target reachability after exit 0. Any mismatch is treated as a failure.