Git Uploader

Pushes a selected Git resource into an existing Git repository. The commits are copied unchanged: the commit SHA, authorship, parents and signatures stay the same, and no commit is created. The resource is published with a Git/v1 access on the target repository, the full ref and the commit, which downloads to the same digest.

Schema

Fields

FieldTypeRequiredDescription
matchCEL expressionnoA CEL boolean expression selecting the resources this uploader handles (resource, component and target are available; test access types with resource.access.isType). When omitted, the default below applies.
repositoryCEL expressionyesURL of the existing target repository in any form a Git/v1 access accepts: a ${…} CEL template or a plain literal.
refCEL expressionyesFull branch or tag ref the commit is pushed to, e.g. refs/heads/main or refs/tags/v1.0.0: a ${…} CEL template or a plain literal (see Refs).

repository and ref are evaluated while the transfer graph is built, so a template that does not evaluate, an invalid repository URL, or a ref that is not a branch or tag fails the transfer before anything is pushed.

Default match

match: resource.access.isType("Git")

The default does not depend on the transfer target: a configured Git uploader pushes Git resources, whether the component version goes to an OCI registry or a CTF archive. A Git resource copied by value becomes a local blob that no longer carries its origin, so it is not selected by default (see Air-gapped transfer).

Origin

The origin of a Git access is the repository path of its source (without scheme, host and port) and its ref. resource.access.toGit() returns it as a map with repository and ref:

AccesstoGit().repositorytoGit().ref
Git https://github.com/org/repo.git, ref refs/heads/mainorg/repo.gitrefs/heads/main

Use it in your own repository template, e.g. to mirror a Git resource below a different host while keeping its path:

repository: ${"https://git.internal.example/" + resource.access.toGit().repository}
ref: refs/heads/main

toGit() needs a Git access. toGit().ref can be a short name (construction does not expand it), so set ref to a full branch or tag ref explicitly. Copying a Git resource as a local blob keeps the archive and the resource digest unchanged and marks it with the media type application/vnd.ocm.software.git.archive.v1+tar+gzip, but does not record the origin, so it is pushed with an explicit repository and ref (see Air-gapped transfer).

Refs

The target ref must be a full branch or tag ref, set explicitly in the uploader config. A short name such as main does not say whether it is a branch or a tag, so it fails the transfer and asks for an explicit ref, e.g. ref: refs/heads/main. HEAD, an empty ref and refs other than branches and tags fail the same way. The archive and the resource digest do not contain the ref, and signing normalization excludes the access.

The ref is then pointed at the commit:

  • A branch is created, or fast-forwarded when the commit descends from its current tip. A branch that does not fast-forward to the commit fails the transfer.
  • A tag is created as a lightweight tag. A tag at another commit fails the transfer.
  • A ref that already points at the commit is left unchanged, so repeated transfers succeed.

The full history of the commit is pushed, so the target repository may be empty. A Git access must be pinned to a commit. The resource digest, if set, is verified against the archive.

Air-gapped transfer

On the connected side, copy Git resources into a CTF archive with a local blob uploader:

- type: localblob.uploader.transfer.config.ocm.software/v1alpha1

The archive keeps its history and is marked with the media type application/vnd.ocm.software.git.archive.v1+tar+gzip, but it does not carry its origin. On the air-gapped side, select it explicitly and set repository and ref:

- type: git.uploader.transfer.config.ocm.software/v1alpha1
  match: resource.access.isType("LocalBlob") && has(resource.access.mediaType) && resource.access.mediaType == "application/vnd.ocm.software.git.archive.v1+tar+gzip"
  repository: https://git.internal.example/mirror/app.git
  ref: refs/heads/main

Local blobs constructed from a Git input have the media type application/x-tgz; match them the same way. Local blobs of resources constructed with OCM v1 hold the files only and are rejected.

Examples

Push one resource to a tag named after the component version:

- type: git.uploader.transfer.config.ocm.software/v1alpha1
  match: resource.name == "sources"
  repository: https://git.internal.example/mirror/app.git
  ref: '${"refs/tags/v" + component.version}'

Credentials for the target are resolved for the Git consumer identity of the target repository URL, as for downloads.