IT Operations
Release Tags and Artifacts: Prove Which Code Was Shipped
Connect release tags to exact commits and deployed artifacts, verify signatures where used, and handle corrections without silently moving an existing release tag.
In this article
Release Tags and Artifacts: Prove Which Code Was Shipped
A release tag is useful only when the team can connect it to the exact code and artifact that reached users. A name such as v2.4.0 is a convenient label, not proof of deployment. Build a release record that includes the tag target, source commit, artifact identity, build context, and observed production version.
This becomes especially important when automated coding and rapid releases produce many branches and builds. Reusing a version name or rebuilding from a moving branch can create several different artifacts that all appear to be the same release.
Know what a Git tag establishes
Git supports lightweight and annotated tags. The official tag documentation explains annotated tag objects and signing options. An annotated tag can carry release metadata; a signature can help verify who signed the tag under the team's trust policy.
Neither establishes that the code is correct or that the build system used it. A valid signature from an unexpected key is also not sufficient authorization. Keep trusted identities, verification steps, and key-lifecycle rules separate from the tag's existence.
For inspection, record both the tag object and the commit it resolves to:
git rev-parse v2.4.0
git rev-parse 'v2.4.0^{commit}'
git show --no-patch v2.4.0Run commands against the intended repository and fetched references. A local tag can differ from a remote reference, so document the source of the observed value.
Build from a fixed commit
The release job should check out an exact commit rather than the current tip of a branch. Record that commit in build metadata and in the deployment record. If the workflow checks out a tag, verify its resolved commit before building.
Capture relevant inputs: dependency lockfile, compiler or runtime version, build configuration, generated-source inputs, and container base image identity where applicable. Do not include secrets in the published metadata. Build reproducibility and artifact provenance require more than a source hash, but a source hash is a necessary starting point.
Suppose tag v2.4.0 points to commit A. A developer fixes a problem on main at commit B, then reruns a job named “release v2.4.0” that builds main. The resulting artifact may contain B while the tag still points to A. The label looks consistent, but the mapping is broken.
Prevent this by passing the fixed commit through the build and deployment stages. Review any step that resolves a branch again after the initial checkout.
Give artifacts their own identity
Use a digest or other immutable artifact identifier in addition to a human-readable version. A container tag can move; its digest identifies a particular image. A download filename can remain unchanged while its bytes change. Verify the identity that the deployment platform actually uses.
Keep a compact release record:
release: v2.4.0
source_commit: exact reviewed commit
artifact_digest: verified output digest
build_run: recorded run identifier
deployment: environment and deployment identifier
observed_version: value checked after deploymentPopulate these fields from observed results, not from the intended job name. A failed deployment should remain a failed deployment even if the release record was created earlier.
Protect tags without making recovery impossible
Use repository controls appropriate to release references. Limit who can create, replace, or delete production release tags, and review the permission available to automation. An assistant that can update source should not automatically gain authority to rewrite historical releases.
Avoid silently moving a published release tag to a new commit. Consumers may have cached the old target, downloaded its artifact, or recorded it in audit evidence. Publish a new corrective version and explain the relationship to the previous release.
If a tag was created incorrectly but never published, use the team's documented correction process. Do not infer that “no one noticed” means it was unused. Check downstream automation and registry activity before treating a reference as disposable.
Verify after deployment
Read the production version through an approved health or metadata surface, then compare it with the release record. For distributed deployments, check enough instances or regions to detect partial rollout. A front-end cache may show an old version even after a backend deployment, so identify what each observed value represents.
Test a representative user journey and monitor the release-specific error budget or rollback criteria. The version endpoint proves identity, not functionality. Keep rollback references immutable too; “previous” should resolve to an exact known artifact rather than a label that can change.
Make incident investigation faster
During a defect investigation, start from the deployed artifact and trace back to its build and source. Do not begin with a guessed release tag based on a date. Preserve the original identifiers even if the version has since been replaced.
Release discipline is a chain of evidence: reviewed source, fixed build input, identified output, and observed deployment. Tags help people navigate that chain, but the artifact mapping is what proves which code was shipped.