Git, CI/CD & GitOpsLXXX · GitOps PruningGitOpsPruning
Prune versus orphan — the two failure modes for absent manifests
What you'll learn
- Distinguish prune from orphan at the controller level
- Identify the production failure each one produces
- Map a symptom to the right failure mode
- Apply the correct detection command for each case
Prerequisites
Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x
Two failure modes produce the same dashboard symptom: the cluster does not match Git. The first is prune — the resource was tracked and was deleted. The second is orphan — the resource was never tracked, or was created by a controller that is no longer managing it, and the cluster still carries it. The remediation paths are opposite. Treating orphan as prune deletes a resource that is needed. Treating prune as orphan lets drift grow.
The two contracts
A prune is a deletion executed by the controller because the resource was in the previous render and is absent from the new render. An orphan is a cluster resource that the controller has not claimed because no controller has the metadata that says “this is mine”.
flowchart LR
R["Git render"] --> D["Diff vs cluster"]
C["Cluster actual"] --> D
D --> P{"In Git, not in cluster?"}
D --> Q{"In cluster, not in Git?"}
P -->|yes| X["Create"]
Q -->|yes| T{"Controller owns it?"}
T -->|yes| Y["Prune — DELETE"]
T -->|no| Z["Orphan — leave"]
The two questions are independent: a resource can be in Git but not in the cluster (a create), in the cluster but not in Git (either a delete or an orphan), in both (no action), or in neither (an unrelated resource that the controller ignores).
What prune catches
Prune catches the removed-from-manifest case:
- A chart drops a deprecated resource.
- A refactor moves a manifest to a different chart.
- A rename produces a diff with one less and one more object.
- A values-merge evaluates to an empty list where the old values produced a non-empty list.
In every case the resource was tracked, the new render no longer references it, and the controller’s prune set contains it. With prune enabled, the controller deletes the cluster resource.
argocd app manifests "$APP_NAME"
The argocd app manifests command prints the rendered manifests
the controller would apply. If a manifest is missing from this
output, the resource is in the prune set.
What orphan catches
Orphan catches the never-tracked case:
- A
kubectl applyfrom an operator outside the GitOps flow. - A Helm install from a different chart not managed by the Application.
- A resource created by an admission controller, a controller bootstrap, or a disaster-recovery runbook.
- A resource whose ownership label was removed by an unrelated process.
In every case the resource exists in the cluster, the GitOps
controller has no metadata that says “this is mine”, and the
controller leaves it alone. Argo CD’s UI surfaces these as
Extra resources on the Application view; Flux has no automatic
orphan detection by default.
Detecting each case
Detection is two commands:
argocd app manifests "$APP_NAME"— the controller’s view of the desired state.kubectl get all -n "$NAMESPACE" -l app.kubernetes.io/instance="$APP_NAME"— the cluster’s view of the Application’s resources.
If a resource appears in the kubectl output but not in the manifests output, the next sync will see it. With prune enabled, the controller will delete it. Without prune, the resource stays as an orphan. The classification is the difference between a deletion and a piece of unmanaged infrastructure.
Production discipline
- Prune is a destructive operation and must be enabled deliberately. The default for new Applications is prune disabled.
- Orphan detection is a separate process. Even without prune, the team should diff cluster resources against the controller’s manifest list at every release.
- A divergence alert is a classification step, not a remediation step. Resolve “what kind of divergence is this?” before deciding what to do.
Cross-course references
- Git, CI/CD & GitOps for Infrastructure Engineers - Part LXXX-01 (What prune is) is the foundation this lesson contrasts with; Part LXXV (Drift) covers the broader divergence family.
- Kubernetes for Production Sysadmins - Part VII (Workloads) is the resource class both failure modes operate on; Part XVI (Operators and Controllers) explains the ownership metadata.
Quiz
Knowledge check · 4 questions
Q1. A team notices a Deployment that is not in the Git manifest but is running in the cluster. The Application has prune enabled. What happens on the next sync?
Q2. Argo CD's UI surfaces orphan resources under the Application's `Extra` section, and Flux has the same default orphan-detection behaviour.
Q3. Name the two commands you would run to classify a divergence alert as prune versus orphan, and what each tells you.
Q4. Classify the divergence and recommend the right remediation.
A production Application reports `OutOfSync` with one missing resource. The team runs `argocd app manifests $APP_NAME` and sees a Deployment named `payment-worker` in the output. They run `kubectl get deploy -n payments -l app.kubernetes.io/instance=payment-api` and see a Deployment named `payment-worker` AND a Deployment named `payment-worker-debug`. The Application has prune enabled. Which is the prune case and which is the orphan case, and what is the right action?
Passing score: 75%. Answers are checked in this browser.