skip to content

An Argo CD Application sets spec.source.targetRevision. What are the practical differences between pointing it at a branch, a tag, and a full commit SHA?

level: middleimportance: should knowfreq 52%

answer

  1. the field is re-resolved, not fixed
  2. how mutable is the name you wrote
  3. branch means the next merge decides
  4. tags move if someone forces them
  5. chart semver ranges are branches in disguise

basics

~20 s

A branch tracks a moving pointer, so any merge changes what Argo CD deploys; a tag is stable but can be moved or deleted by whoever owns the repository; a full commit SHA is immutable, so the deployed content cannot change without editing the Application itself.

solid answer

~50 s

`targetRevision` is resolved to a commit on every refresh, so the guarantee you get depends on how mutable the thing you named is. A **branch** (or `HEAD`, meaning the repo's default branch) means every merge is a deploy — that is exactly what continuous delivery wants for a dev cluster, and exactly what makes production surprising. A **tag** is a stable name for a release, but Git tags are movable and deletable, so it is a convention rather than a guarantee unless the host protects them. A **full commit SHA** is content-addressed and immutable: the Application deploys that tree and nothing else, and rolling forward requires changing the Application manifest, which makes the promotion itself reviewable. For a Helm chart repository the same field is a chart version, where a floating range like `1.2.*` reintroduces exactly the moving-target problem. Most teams run branches in dev and pinned tags or SHAs in production.

go deeper

for a junior

Know the accepted values — branch, tag, commit SHA, HEAD, or a Helm chart version — and that pointing at a branch means every merge to it changes what is deployed.

for a middle

Explain that the revision is re-resolved on each refresh, why a tag is a convention rather than a guarantee, and how a chart semver range recreates the same moving-target behaviour.

for a senior

Argue the per-environment gradient and show how a pinned SHA turns promotion into a reviewable change, including what has to update it and how you investigate an unexpected revision change.

for a principal

Own the promotion model this implies across many apps: who or what is allowed to move a pinned reference, how that is reviewed and audited, and what it costs teams in latency.

## What the field actually resolves to `spec.source.targetRevision` is not a fixed pointer to content; it is a *query* that Argo CD re-resolves against the repository on every refresh — roughly every three minutes by default, and immediately when a repository webhook arrives. The value you write determines how often the answer to that query can change underneath you. ## Branch (including HEAD) ```yaml source: repoURL: https://github.com/acme/manifests.git path: apps/checkout/overlays/dev targetRevision: main ``` A branch name means "whatever the tip of that branch is right now". Combined with `syncPolicy.automated`, merging to `main` *is* the deploy. `HEAD` is the same idea, resolved to the repository's default branch. The strength is immediacy and zero ceremony. The weakness is that the deployed content is decided by whoever merges next, and the Application manifest gives no evidence of what is running. Two clusters pointing at the same branch can be running different commits simply because they refreshed at different moments. And a rollback means pushing a revert commit — you cannot roll back by editing the Application, because the Application does not name a version. ## Tag A tag such as `v1.8.3` gives the Application a human-meaningful, normally stable name. It is the natural fit for promotion: cut a release, tag it, point the production Application at the tag. Argo CD's history and the manifest both now say something intelligible about what is deployed. The caveat candidates miss is that a Git tag is a mutable reference. `git tag -f` plus a force-push relocates it, and nothing in Argo CD notices anything other than "the revision resolved to a different commit". An annotated, signed and host-protected tag is much stronger than a lightweight one, but the immutability lives in your repository host's protection rules, not in Git and not in Argo CD. ## Full commit SHA ```yaml source: targetRevision: 9f2c1de5a3b64c7ef4a02f8b1cd7e6a5b0d3f214 ``` A full 40-character SHA is content-addressed: that string can only ever mean that tree. The Application is now a precise, auditable statement of what production runs, and a rollback is a one-line edit back to the previous SHA. This is the same reasoning as pinning a container image by digest instead of by tag. The cost is that something must now update the SHA. In practice that something is a promotion pipeline or an image-update automation opening a pull request against the environment's Application manifest — which is the point: the promotion becomes a reviewable change rather than an invisible consequence of a merge somewhere else. Note that Argo CD also accepts short SHAs and, for Git sources, certain other revision expressions; a full SHA is what you want when the goal is an unambiguous audit trail. ## Helm repositories are the same problem in different clothes When `repoURL` is a Helm chart repository or an OCI registry and you set `chart:` rather than `path:`, `targetRevision` is the *chart version*, and it accepts semver ranges. `targetRevision: 1.2.*` looks tidy and behaves exactly like a branch: a new upstream patch release deploys itself. For anything you care about, pin the exact chart version. ## Choosing per environment The common shape is a gradient rather than one rule: - **dev / preview** — track a branch. Fast feedback matters more than knowing precisely what is running. - **staging** — track a release branch or a tag, so what you test is what you will ship. - **production** — pin a tag or a SHA, updated by an explicit, reviewed change. The deeper principle is that promotion should be a *change to a pinned reference*, not the passage of time. If every environment tracks `main`, you do not have environments; you have one environment with lag. ## The diagnostic angle When an Application deployed something nobody expected, the first question is what `targetRevision` resolves to and when it last changed. `argocd app get` shows the resolved revision, and the app's sync history records which revisions were synced, so you can tell "the branch moved" from "someone changed the Application".

  • If production tracks a branch, how do you roll back a bad release?
    By pushing a revert commit to that branch and waiting for the next refresh or forcing one — you cannot roll back by editing the Application, because it names no version. `argocd app rollback` can re-sync a previous history entry, but the branch still points at the bad commit, so the next self-heal or refresh drags it forward again unless Git is fixed.
  • Argo CD resolved targetRevision to a different commit but nobody merged anything. What could have happened?
    The name you pinned moved: a tag was force-updated or recreated, or the branch was reset or force-pushed. Argo CD only records that the revision resolved differently, so the investigation belongs in the repository host's audit log. Protected tags, or pinning a full SHA instead, removes the ambiguity.
  • Why do teams prefer a commit SHA in the Application over a floating tag, given the extra automation it needs?
    Because the Application manifest becomes the record of what is deployed, and changing it becomes a reviewable pull request with an approver and an audit trail. The extra automation — a promotion job or image-update controller opening that PR — is the same work the floating tag was doing invisibly, made explicit.

saying these in an interview costs you the question

  • Believing Git tags are immutable
  • Thinking targetRevision is resolved once at creation
  • Treating HEAD as a special Argo CD keyword rather than the default branch
  • Using a semver range for a production chart version
  • Assuming every environment should track main

context