Documentation
Changed-Only Diffs
Multi-Application diffs use changed-only selection by default. drydock maps changed files to Application inputs and renders only the affected Applications when ownership is clear.
If any changed file is unowned or ambiguous, non-strict mode warns and renders
all Applications (diff.changed-only-incomplete). This preserves correctness
at the cost of a broader diff.
drydock also compares the resolved Argo CD settings of the two sides directly,
before path ownership is evaluated, so a settings change counts even when the
changed settings file is excluded by --changed-only-ignore, as long as another
changed path survives the filters. What it selects depends on what reads the
setting.
A setting that every render or diff reads renders all Applications, with its own
diagnostic (diff.changed-only-settings): the tracking method, instance label,
or installation ID, Kustomize build options, Helm value file schemes, a CMP
definition, resource exclusions or inclusions, compare options, a resource
customization a diff or health check reads (ignoreDifferences,
knownTypeFields, health Lua, useOpenLibs), or which repository Secrets
enable OCI for an OCI repository URL. Unlike an unowned-path fallback, this
render-all is exempt from --strict-changed-only and --strict: rendering
every Application is the complete answer to a settings change, not a gap in
ownership.
A repository or cluster Secret that is added, removed, or changed reaches
Applications only through project validation, so it selects only the
Applications that use it, reported with diff.changed-only-settings-scoped
(also strict-exempt). A repository Secret selects every Application with a
source whose repoURL matches its URL, chart and $ref sources included, and
a project-scoped deny pattern (!url) every Application in its project. A
deny pattern scoped to default reaches every Application: with no AppProject
declared, each one validates against the implicit default project, whatever
project it names. A cluster Secret selects every Application whose destination
names the cluster or points at its server, and a project-scoped cluster Secret
every Application in that project. Such a change does not excuse an unowned
changed path: that still renders all Applications with
diff.changed-only-incomplete, and
--strict-changed-only still fails.
Settings that no build, diff, or test reads select nothing:
resource.ignoreResourceUpdatesEnabled,
resource.customizations.ignoreResourceUpdates.*, and action Lua
(resource.customizations.actions.*). They do not excuse an unowned changed
path either.
A changed AppProject selects every Application in that project, not just the
Application that owns the AppProject file: tightening sourceRepos,
destinations, or resource lists re-validates each member, so changed-only
reports the same project diagnostics as a full diff. Declaring the first
AppProject or removing the last renders all Applications instead, with its own
diagnostic (diff.changed-only-projects): with no AppProject every
Application validates against the implicit default project, whatever
project it names. Like diff.changed-only-settings, this render-all is exempt
from --strict-changed-only and --strict. With --project-diagnostics off,
AppProject changes select nothing extra.
Commands
Use the default behavior:
drydock diff apps --repo . --ref HEAD --ref-orig main
Render everything explicitly:
drydock diff apps --repo . --ref HEAD --ref-orig main --changed-only=false
Fail when ownership cannot be proven:
drydock diff apps --repo . --ref HEAD --ref-orig main --strict-changed-only
Scope the changed paths considered by ownership mapping:
drydock diff apps \
--repo . \
--ref HEAD \
--ref-orig main \
--changed-only-include 'apps/**' \
--changed-only-ignore '.github/**'
Include and ignore globs are repository-relative. If no include globs are set, all changed paths are considered. Ignore globs are applied after includes, so ignore wins. When every changed path is filtered out, drydock reports an empty diff instead of rendering the fleet.
diff app selects one requested Application directly and does not use
changed-only Git path filtering.
Changed-Only Ignore vs Discover Ignore
--changed-only-ignore and --discover-ignore share glob syntax but act at
different stages. --changed-only-ignore filters which changed paths are
considered for changed-only ownership; the files themselves are still
discovered and decoded. --discover-ignore removes matching files from
repository discovery before decoding, on every command that discovers
Applications.
The two flag families stay independent under --strict-changed-only: a
discover-ignored file that changes still surfaces as an unowned changed path
unless it is also --changed-only-ignored. Repositories that commit
non-deployable YAML usually want the same glob in both flags:
drydock diff apps \
--repo . \
--ref HEAD \
--ref-orig main \
--strict-changed-only \
--discover-ignore 'templates/**' \
--changed-only-ignore 'templates/**'
Mental Model
Changed-only behavior is Argo Application-aware. Shared resources from different Applications remain separate diff identities; drydock does not collapse overlapping Applications into one owner.
Ownership follows the local Kustomize input graph, not only
spec.source.path. An Application whose path is an overlay such as
apps/demo/overlays/staging also owns the files that overlay reaches through
resources, bases, components, helmCharts.valuesFile,
helmCharts.additionalValuesFiles, and local patch, generator, and transformer
paths, plus the components and patch files the Application adds through
spec.source.kustomize.components and spec.source.kustomize.patches.
Editing apps/demo/base/helm-release/values.yaml therefore selects every
overlay that includes that base. Only sources that render from the local
checkout contribute: sources fetched from another repository, repo-mapped to
another checkout, or stored in OCI do not. Plugin sources contribute when
their path holds a kustomization, because AVP and native Kustomize plugin
compatibility build it with Kustomize; explicit Helm and Directory sources do
not.
A Helm source also owns each helm.valueFiles and helm.fileParameters[].path
entry it resolves, even when the resolved path escapes spec.source.path, bound
to the repository root. A glob value file owns its static leading directory, not
the files the glob expands to. Entries that use environment substitution ($)
own nothing. A $ref value file or file parameter owns its resolved path when
the ref root is the local tree: a
self-repository
ref, a
ref --repo-mapped to the repository root, or one sharing the repository and
revision of a source whose path is in the checkout. A ref drydock fetches,
including a pinned commit SHA or OCI, owns nothing.
An Application’s argocd.argoproj.io/manifest-generate-paths annotation adds
ownership that drydock cannot infer, such as the files an exec or container
plugin reads. Entries use Argo CD’s syntax and never own the repository root.
A declared path counts as owned like any other, so every plugin Application
that reads it must declare it. See
Declare plugin inputs
.
An Application rendered by a parent Application (app-of-apps, including
Applications generated by an ApplicationSet the parent renders) is selected
whenever its parent is, transitively, so any change the parent owns selects
every child it renders. Editing a Helm app-of-apps parent’s values file, for
example, can change a child’s spec.source.path without touching any file
under the child’s own source path; drydock still selects the child because it
selects the parent. An Application declared by a --discover-kustomize
directory or a policy-bootstrap entrypoint also owns that directory’s Kustomize
graph.
If the Kustomize graph cannot be read, for example because a kustomization
escapes the repository or fails to parse, the Application keeps only its
spec.source.path ownership. A change only that graph would have owned then
stays unowned and falls back to rendering all Applications. A change another
Application’s graph also reaches selects only that Application.
Path filters are explicit command or workflow policy. Keep filters narrow in repositories that use plugins or unusual generation paths, because an ignored file is no longer eligible to trigger a render.
For diff outputs and exit codes, see Output controls and Compatibility .