From 7490cecc11ddd91cbba8370df5c014e95b528b98 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Sun, 14 Dec 2025 17:28:48 -0500 Subject: [PATCH 1/7] Bring .helmignore to parity with .gitignore for Charts v3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit /## Summary This HIP proposes bringing `.helmignore` file targeting semantics to full parity with `.gitignore` syntax and matching rules for Helm Charts v3. /## Problem Users expect `.helmignore` to work like `.gitignore`, but the current implementation has critical divergences: - Broken negation: Whitelist patterns like `/*` + `!Chart.yaml` fail because negation logic is inverted (helm#3622, helm#8688) - No `**` globs: Recursive patterns are explicitly unsupported - First-match semantics: Helm stops at first match; Git uses last-match-wins These issues have persisted for years (PR #12265 stalled since 2023) because fixing them is a breaking change. /## Solution Scope the fix to Charts v3 (per HIP-0020), providing: - Full `.gitignore` pattern syntax (`**`, `!`, escape sequences) - Last-match-wins rule evaluation - Clean opt-in boundary—v2 charts unchanged, v3 charts get correct behavior /## References - Depends on: HIP-0020 (Charts v3 Enablement) - Implementation approach: Use go-git's gitignore (same as FluxCD's .sourceignore) Signed-off-by: Scott Rigby --- hips/hip-9999.md | 346 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 hips/hip-9999.md diff --git a/hips/hip-9999.md b/hips/hip-9999.md new file mode 100644 index 00000000..63820b11 --- /dev/null +++ b/hips/hip-9999.md @@ -0,0 +1,346 @@ +--- +hip: 9999 +title: "Bring .helmignore to parity with .gitignore file targeting syntax" +authors: ["Scott Rigby "] +created: "2025-12-14" +type: "feature" +status: "draft" +requires: ["HIP-0020"] +replaces: +superseded-by: +--- + +## Abstract + +This proposal brings `.helmignore` file targeting semantics to full parity with `.gitignore` syntax and matching rules for Helm Charts v3. The current `.helmignore` implementation diverges from `.gitignore` in critical ways—most notably in rule evaluation order (first-match vs. last-match), negation pattern behavior, and lack of `**` recursive glob support. These differences cause confusion and bugs for users who reasonably expect `.helmignore` to behave like `.gitignore`. By scoping this change to Charts v3 (per [HIP-0020][hip-0020]), existing charts continue to work unchanged while v3 charts opt into consistent, predictable ignore behavior. + +## Motivation + +Users familiar with `.gitignore` expect the same behavior from `.helmignore`. The current divergence causes: + +1. **Broken negation patterns**: Users cannot use whitelist-style patterns (e.g., `/*` then `!Chart.yaml`) because the current implementation has inverted negation semantics ([#8688], [#3622], [#1776]). + +2. **Missing recursive globs**: The `**` pattern is explicitly unsupported, forcing verbose workarounds for common cases like `**/test/` ([#12592]). + +3. **Unexpected first-match behavior**: Git uses "last matching rule wins"; Helm stops at the first match. This breaks patterns that progressively refine what to exclude. + +4. **Scope confusion**: Users expect `.helmignore` to only affect `helm package`, but it affects all commands including `template`, `install`, and `upgrade` ([#6075], [helm-www#1171]). + +5. **Documentation gaps**: Current docs don't clearly explain limitations or differences from `.gitignore` ([#4638], [helm-www#1312]). + +### Evidence of User Pain + +A comprehensive search of helm/helm issues reveals **27 directly related issues** and **5 pull requests**. Key themes: + +- **Pattern matching logic**: [#8688], [#3622], [#1776], [#12592] +- **Scope/behavior confusion**: [#6075], [#3050], [#10764] +- **Feature requests for global ignore**: [#1674], [#5675] +- **Documentation issues**: [#4638], [helm-www#1171], [helm-www#1312], [helm-www#1460] + +The recurring user expectation is clear: `.helmignore` should work like `.gitignore`. + +## Rationale + +### Why .gitignore Parity? + +1. **Reduced cognitive load**: Developers already know `.gitignore` semantics. Aligning `.helmignore` eliminates a class of surprises. + +2. **Well-documented spec**: Git's ignore format is [thoroughly documented][git-gitignore] and battle-tested across millions of repositories. + +3. **Ecosystem consistency**: Tools like Docker (`.dockerignore`), npm (`.npmignore`), and FluxCD (`.sourceignore`) all follow `.gitignore` semantics. + +### Why Charts v3? + +Per [HIP-0020][hip-0020], Charts v3 provides a clean opt-in boundary for breaking changes: + +1. **Breaking change isolation**: Charts explicitly declare `apiVersion: v3`, accepting new semantics. Charts v2 behavior is preserved unchanged. + +2. **No forced migration**: Existing charts continue to work. Users migrate on their own schedule. + +3. **Independent evolution**: Chart changes are decoupled from Helm version, allowing adequate time for testing and adoption. + +This is the appropriate scope because changing `.helmignore` semantics would break charts that depend on current (albeit buggy) behavior. + +## Specification + +### Behavioral Parity with .gitignore + +Charts v3 `.helmignore` files SHALL support the full `.gitignore` pattern format as documented at [git-scm.com/docs/gitignore][git-gitignore]: + +#### Pattern Types + +| Pattern | Behavior | +| ----------- | ------------------------------------------------ | +| Blank lines | Ignored (separators for readability) | +| `# comment` | Lines starting with `#` are comments | +| `\#` | Escaped `#` matches literal `#` filename | +| `!pattern` | Negation—re-includes previously excluded matches | +| `/pattern` | Leading `/` anchors pattern to chart root | +| `pattern/` | Trailing `/` matches directories only | +| `*` | Matches anything except `/` | +| `?` | Matches any single character except `/` | +| `[a-z]` | Character class matching | +| `**` | Recursive glob (see below) | +| `\ ` | Escaped trailing space (preserved) | +| `\!` | Escaped `!` matches literal `!` filename | + +#### Recursive Glob Semantics (`**`) + +- `**/foo` — matches `foo` in all directories +- `foo/**` — matches everything inside `foo/` +- `a/**/b` — matches `a/b`, `a/x/b`, `a/x/y/b`, etc. + +#### Rule Evaluation Order + +**Last matching rule wins**. All rules are evaluated; the final matching rule determines whether a path is included or excluded. This enables patterns like: + +``` +# Exclude everything +/* + +# But include these +!Chart.yaml +!values.yaml +!templates/ +``` + +#### Negation Behavior + +- `!pattern` re-includes files that match, reversing a prior exclusion +- **Limitation**: Cannot re-include a file if its parent directory was excluded (Git skips listing excluded directories for performance) + +#### Scope Clarification + +Helm has no concept of staging or committing files. This proposal addresses **file targeting syntax and semantics only**—specifically, which files are included/excluded during chart operations. Git's behavior around staged/committed files does not apply. + +### Technical Requirements + +1. **Parser/Matcher**: Implement a `.gitignore`-compatible lexer, parser, and matcher supporting all pattern types above. + +2. **Last-match semantics**: Evaluate all rules; final matching rule determines outcome. + +3. **Path normalization**: Normalize paths to forward slashes for cross-platform consistency. + +4. **Directory short-circuit**: Once a directory is excluded, skip traversing its contents (matches Git's performance optimization). + +5. **Self-exclusion**: `.helmignore` MAY be automatically excluded (unlike current behavior per [#9436]). + +### Integration Points + +Apply `.gitignore`-parity matching in all chart file operations: + +- `helm package` +- `helm lint` +- `helm template` +- `helm install` / `helm upgrade` (for local charts) +- `.Files.Get` / `.Files.Glob` (file access in templates) + +### Gating + +- **Charts v3 (`apiVersion: v3`)**: New `.gitignore`-parity semantics +- **Charts v2 (`apiVersion: v2`)**: Existing behavior unchanged + +## Backwards Compatibility + +### Charts v2 + +No behavior change. Existing `.helmignore` files continue to work exactly as before, preserving compatibility for all current charts. + +### Charts v3 + +Charts opting into v3 accept new `.helmignore` semantics. Potential breaking changes for charts migrating from v2: + +| Current Behavior | New Behavior | Migration Impact | +| ------------------------ | -------------------------- | ------------------------------------------------------------ | +| First-match evaluation | Last-match evaluation | Patterns relying on early termination may behave differently | +| Negation inverts match | Negation re-includes | Whitelist patterns will finally work correctly | +| `**` causes error | `**` works | No breakage (feature addition) | +| Trailing spaces stripped | Preserved with `\ ` | Unlikely to affect real charts | +| No escape sequences | `\#`, `\!`, `\ ` supported | No breakage (feature addition) | + +### Migration Guidance + +1. **Test with v3**: Before changing `apiVersion`, test charts with new semantics +2. **Review negation patterns**: Patterns with `!` may now work as originally intended +3. **Simplify patterns**: `**` globs can replace verbose directory-specific patterns + +## Security Implications + +None. This change only affects which local files are considered during chart operations. It does not: + +- Introduce new attack surfaces +- Add remote dependencies +- Change network behavior +- Affect chart signing or verification + +## How to Teach This + +### Documentation Updates + +1. **Primary statement**: "Charts v3 `.helmignore` uses identical pattern rules to `.gitignore`." + +2. **Link to Git documentation**: Reference [git-scm.com/docs/gitignore][git-gitignore] as the canonical spec. + +3. **Migration guide**: Document behavior differences between v2 and v3. + +4. **Examples**: Provide side-by-side comparisons showing: + - Whitelist patterns (`/*`, `!Chart.yaml`) + - Recursive globs (`**/test/`) + - Last-match ordering + +### Release Notes + +- Highlight UX improvement for users expecting `.gitignore` behavior +- Link to this HIP and HIP-0020 for context +- Emphasize opt-in nature via Charts v3 + +### Example Patterns + +```gitignore +# Comments start with # + +# Ignore all dotfiles +.* + +# But keep .helmignore itself +!.helmignore + +# Ignore test directories anywhere +**/test/ +**/tests/ + +# Ignore IDE files +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# Whitelist approach: exclude everything, then include specifics +/* +!Chart.yaml +!values.yaml +!values.schema.json +!templates/ +!charts/ +!crds/ +!files/ + +# Directory-only patterns (trailing slash) +vendor/ +node_modules/ + +# Anchored to root (leading slash) +/local-only.yaml +``` + +## Reference Implementation + +Implementation will be gated behind Charts v3 as specified in [HIP-0020][hip-0020]: + +1. New matcher package under `internal/chart/v3/ignore/` implementing `.gitignore` semantics +2. Integration with v3 chart loader +3. Comprehensive test suite covering: + - All pattern types from Git documentation + - Edge cases from reported issues ([#8688], [#3622], [#1776]) + - Cross-platform path handling +4. Migration tests validating v2 charts remain unchanged +5. Update `helm create` scaffold for v3 charts (once [PR #31592][pr-31592] merges) to generate a `.helmignore` demonstrating gitignore-parity patterns + +Implementation details (library choice, architecture) are intentionally left to implementers. A separate implementation research document will evaluate options including existing Go libraries and FluxCD's `.sourceignore` implementation. + +## Rejected Ideas + +### Shell out to `git check-ignore` + +Calling the `git` binary would provide perfect behavioral parity. Rejected because: + +- Helm binaries must not have external runtime dependencies +- Adds complexity for containerized/minimal environments +- Performance overhead for repeated invocations + +### Partial parity (e.g., add `**` but keep first-match) + +Rejected because partial fixes would leave confusing inconsistencies. Users expect `.gitignore` behavior; half-measures perpetuate the problem. + +### Change behavior for all chart versions + +Rejected because it would break existing charts that depend on current (albeit buggy) semantics. Charts v3 provides clean isolation for breaking changes. + +## Open Issues + +1. **Self-exclusion default**: Should `.helmignore` be automatically excluded in v3? (Currently requires explicit entry per [#9436]) + +2. **Global ignore file**: Users have requested `~/.helmignore` support ([#1674], [#5675]). This is out of scope for this HIP but could be addressed separately. + +3. **Scope refinement**: Should `.helmignore` have different behavior for `helm package` vs. other commands? ([#6075], [#3050]). Out of scope for this HIP. + +## References + +### Helm HIPs + +- [HIP-0020: Charts v3 Enablement][hip-0020] + +### Git Documentation + +- [git-scm.com/docs/gitignore][git-gitignore] + +### Issues Directly Addressed by This HIP + +These issues are resolved by implementing `.gitignore` pattern matching parity: + +- [#8688][#8688] — Negation semantics are inverted; `!pattern` ignores non-matches instead of re-including matches. +- [#3622][#3622] — Whitelist patterns (`/*` then `!Chart.yaml`) fail with "chart metadata missing" due to broken negation logic. +- [#1776][#1776] — Pattern `.*` incorrectly matched the current directory, breaking charts. Shows user expectation of gitignore behavior. +- [#12592][#12592] — Patterns like `charts/*/README.md` don't work; `**` glob support and improved matching would help. +- [#12265][#12265] (PR) — Attempted partial fix for negation, stalled 2 years as a breaking change. This HIP provides the proper scope via Charts v3. + +### Issues Out of Scope (Context Only) + +These issues concern _when_ `.helmignore` applies, not pattern syntax. Included for context but not addressed by this HIP: + +- [#6075][#6075] — Users expected ignore to affect only `helm package`, but it affects all commands. This is intentional; HIP clarifies but doesn't change this. +- [#3050][#3050] — Files in `.helmignore` are inaccessible to `.Files.Get`. Architectural issue about ignore scope, not pattern matching. +- [#10764][#10764] — README files consume release storage; users want "exclude from release but include in package." Requires new scope distinction. +- [#9436][#9436] — `.helmignore` doesn't exclude itself from packages. Listed as open question for Charts v3. + +### Feature Requests (Out of Scope) + +- [#1674][#1674], [#5675][#5675] — Global `~/.helmignore` support. Already partially implemented; could adopt gitignore parity separately. +- [#989][#989] — Default patterns for editor swap files. Addressed previously; shows user expectation of sensible defaults. + +### Documentation Issues + +These show user confusion that better docs (and gitignore parity) would reduce: + +- [#4638][#4638] — Requested more `.helmignore` documentation; shows need for clearer syntax docs. +- [helm-www#1171][helm-www#1171] — Docs say ignore affects "packaging" only, but it affects all operations. Needs correction regardless of HIP. +- [helm-www#1312][helm-www#1312] — Docs don't specify `.helmignore` must be in chart root, not working directory. +- [helm-www#1460][helm-www#1460] — Example pattern `/temp*` broke charts by matching `templates/`. Shows need for better examples. + +### Other Related PRs + +- [#13293][#13293] — Fix for broken symlinks in `.helmignore`. Tangentially related to ignore handling. + + + +[hip-0020]: https://github.com/helm/community/blob/main/hips/hip-0020.md +[pr-31592]: https://github.com/helm/helm/pull/31592 +[git-gitignore]: https://git-scm.com/docs/gitignore +[#8688]: https://github.com/helm/helm/issues/8688 +[#3622]: https://github.com/helm/helm/issues/3622 +[#1776]: https://github.com/helm/helm/issues/1776 +[#12592]: https://github.com/helm/helm/issues/12592 +[#6075]: https://github.com/helm/helm/issues/6075 +[#3050]: https://github.com/helm/helm/issues/3050 +[#9436]: https://github.com/helm/helm/issues/9436 +[#10764]: https://github.com/helm/helm/issues/10764 +[#1674]: https://github.com/helm/helm/issues/1674 +[#5675]: https://github.com/helm/helm/issues/5675 +[#989]: https://github.com/helm/helm/issues/989 +[#4638]: https://github.com/helm/helm/issues/4638 +[#12265]: https://github.com/helm/helm/pull/12265 +[helm-www#1171]: https://github.com/helm/helm-www/issues/1171 +[helm-www#1312]: https://github.com/helm/helm-www/issues/1312 +[helm-www#1460]: https://github.com/helm/helm-www/issues/1460 +[#13293]: https://github.com/helm/helm/pull/13293 From 4c62fb4b819b6d4e037359969fbb1e978e0ab933 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Thu, 18 Dec 2025 07:54:34 -0500 Subject: [PATCH 2/7] clarify reasoning language Co-authored-by: Andrew Block Signed-off-by: Scott Rigby --- hips/hip-9999.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 63820b11..8484cb1d 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -43,7 +43,7 @@ The recurring user expectation is clear: `.helmignore` should work like `.gitign ### Why .gitignore Parity? -1. **Reduced cognitive load**: Developers already know `.gitignore` semantics. Aligning `.helmignore` eliminates a class of surprises. +1. **Reduced cognitive load**: Developers already know `.gitignore` semantics. Aligning `.helmignore` enables existing knowledge and patterns to be reused with Helm. 2. **Well-documented spec**: Git's ignore format is [thoroughly documented][git-gitignore] and battle-tested across millions of repositories. From d0277193aeb02436f6652ee6a8092e3905e24c23 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Fri, 23 Jan 2026 17:17:50 -0500 Subject: [PATCH 3/7] Clarify behavior scope, open questions, and documentation via this HIP Signed-off-by: Scott Rigby --- hips/hip-9999.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 8484cb1d..c8b21914 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -24,9 +24,7 @@ Users familiar with `.gitignore` expect the same behavior from `.helmignore`. Th 3. **Unexpected first-match behavior**: Git uses "last matching rule wins"; Helm stops at the first match. This breaks patterns that progressively refine what to exclude. -4. **Scope confusion**: Users expect `.helmignore` to only affect `helm package`, but it affects all commands including `template`, `install`, and `upgrade` ([#6075], [helm-www#1171]). - -5. **Documentation gaps**: Current docs don't clearly explain limitations or differences from `.gitignore` ([#4638], [helm-www#1312]). +4. **Documentation gaps**: Current docs don't clearly explain limitations or differences from `.gitignore` ([#4638], [helm-www#1312]). Users expect `.helmignore` to only affect `helm package`, but it affects all commands including `template`, `install`, and `upgrade` ([#6075], [helm-www#1171]). ### Evidence of User Pain @@ -188,6 +186,8 @@ None. This change only affects which local files are considered during chart ope - Recursive globs (`**/test/`) - Last-match ordering +5. **Improve v2 and v3 documentation**: Existing `.helmignore` documentation is insufficient, leading to end user confusion, so this should be documented as well. + ### Release Notes - Highlight UX improvement for users expecting `.gitignore` behavior @@ -269,11 +269,7 @@ Rejected because it would break existing charts that depend on current (albeit b ## Open Issues -1. **Self-exclusion default**: Should `.helmignore` be automatically excluded in v3? (Currently requires explicit entry per [#9436]) - -2. **Global ignore file**: Users have requested `~/.helmignore` support ([#1674], [#5675]). This is out of scope for this HIP but could be addressed separately. - -3. **Scope refinement**: Should `.helmignore` have different behavior for `helm package` vs. other commands? ([#6075], [#3050]). Out of scope for this HIP. +None. ## References @@ -302,7 +298,7 @@ These issues concern _when_ `.helmignore` applies, not pattern syntax. Included - [#6075][#6075] — Users expected ignore to affect only `helm package`, but it affects all commands. This is intentional; HIP clarifies but doesn't change this. - [#3050][#3050] — Files in `.helmignore` are inaccessible to `.Files.Get`. Architectural issue about ignore scope, not pattern matching. - [#10764][#10764] — README files consume release storage; users want "exclude from release but include in package." Requires new scope distinction. -- [#9436][#9436] — `.helmignore` doesn't exclude itself from packages. Listed as open question for Charts v3. +- [#9436][#9436] — `.helmignore` doesn't exclude itself from packages. This is intentional becuase `.helmignore` is used for more than packaging, so various workflows could be disrupted (see https://github.com/helm/helm/issues/9436#issuecomment-792795063). Documentation update via this HIP should clarify this. ### Feature Requests (Out of Scope) From 844191fe70a810a435366ead323130e580dd42fc Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 26 Jan 2026 17:57:43 -0500 Subject: [PATCH 4/7] Address @gjenkins8 review: clarify scope, add Design Intent section Signed-off-by: Scott Rigby --- hips/hip-9999.md | 71 +++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index c8b21914..deb3c5d5 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -24,7 +24,7 @@ Users familiar with `.gitignore` expect the same behavior from `.helmignore`. Th 3. **Unexpected first-match behavior**: Git uses "last matching rule wins"; Helm stops at the first match. This breaks patterns that progressively refine what to exclude. -4. **Documentation gaps**: Current docs don't clearly explain limitations or differences from `.gitignore` ([#4638], [helm-www#1312]). Users expect `.helmignore` to only affect `helm package`, but it affects all commands including `template`, `install`, and `upgrade` ([#6075], [helm-www#1171]). +4. **Documentation gaps**: Current docs don't clearly explain limitations or differences from `.gitignore` ([#4638], [helm-www#1312]). ### Evidence of User Pain @@ -32,7 +32,6 @@ A comprehensive search of helm/helm issues reveals **27 directly related issues* - **Pattern matching logic**: [#8688], [#3622], [#1776], [#12592] - **Scope/behavior confusion**: [#6075], [#3050], [#10764] -- **Feature requests for global ignore**: [#1674], [#5675] - **Documentation issues**: [#4638], [helm-www#1171], [helm-www#1312], [helm-www#1460] The recurring user expectation is clear: `.helmignore` should work like `.gitignore`. @@ -57,30 +56,21 @@ Per [HIP-0020][hip-0020], Charts v3 provides a clean opt-in boundary for breakin 3. **Independent evolution**: Chart changes are decoupled from Helm version, allowing adequate time for testing and adoption. -This is the appropriate scope because changing `.helmignore` semantics would break charts that depend on current (albeit buggy) behavior. +This is the appropriate scope because changing `.helmignore` semantics would break charts that depend on current (albeit surprising) behavior. ## Specification ### Behavioral Parity with .gitignore -Charts v3 `.helmignore` files SHALL support the full `.gitignore` pattern format as documented at [git-scm.com/docs/gitignore][git-gitignore]: - -#### Pattern Types - -| Pattern | Behavior | -| ----------- | ------------------------------------------------ | -| Blank lines | Ignored (separators for readability) | -| `# comment` | Lines starting with `#` are comments | -| `\#` | Escaped `#` matches literal `#` filename | -| `!pattern` | Negation—re-includes previously excluded matches | -| `/pattern` | Leading `/` anchors pattern to chart root | -| `pattern/` | Trailing `/` matches directories only | -| `*` | Matches anything except `/` | -| `?` | Matches any single character except `/` | -| `[a-z]` | Character class matching | -| `**` | Recursive glob (see below) | -| `\ ` | Escaped trailing space (preserved) | -| `\!` | Escaped `!` matches literal `!` filename | +Charts v3 `.helmignore` files should support the full `.gitignore` pattern format as documented at [git-scm.com/docs/gitignore][git-gitignore]. + +#### Design Intent + +`.helmignore` is intended to follow Git's `.gitignore` file pattern matching semantics as documented at the time of this HIP's acceptance. These semantics have been intentionally stable for many years, and familiarity with them is a primary goal of this proposal. + +If Helm's `.helmignore` behavior diverges from Git's documented `.gitignore` behavior, that divergence should be treated as a bug and corrected—unless the divergence is explicitly documented in this proposal (see Scope Clarification). + +**Future Git changes**: If Git were to introduce incompatible changes to `.gitignore` matching semantics in the future, Helm would evaluate and explicitly decide whether to adopt those changes. Helm does not implicitly inherit future Git behavior changes. #### Recursive Glob Semantics (`**`) @@ -93,7 +83,7 @@ Charts v3 `.helmignore` files SHALL support the full `.gitignore` pattern format **Last matching rule wins**. All rules are evaluated; the final matching rule determines whether a path is included or excluded. This enables patterns like: ``` -# Exclude everything +# Exclude all top-level entries (files and directories) /* # But include these @@ -111,6 +101,12 @@ Charts v3 `.helmignore` files SHALL support the full `.gitignore` pattern format Helm has no concept of staging or committing files. This proposal addresses **file targeting syntax and semantics only**—specifically, which files are included/excluded during chart operations. Git's behavior around staged/committed files does not apply. +#### File Location + +Charts v3 `.helmignore` is loaded from the chart root directory only. Unlike `.gitignore`, which supports recursive ignore files in subdirectories within a repository, Helm loads `.helmignore` only from the chart root. Patterns in the root `.helmignore` apply to the entire chart tree. + +Recursive `.helmignore` loading within a chart (matching Git's nested `.gitignore` behavior) is a potential future enhancement but is out of scope for this HIP. + ### Technical Requirements 1. **Parser/Matcher**: Implement a `.gitignore`-compatible lexer, parser, and matcher supporting all pattern types above. @@ -121,11 +117,9 @@ Helm has no concept of staging or committing files. This proposal addresses **fi 4. **Directory short-circuit**: Once a directory is excluded, skip traversing its contents (matches Git's performance optimization). -5. **Self-exclusion**: `.helmignore` MAY be automatically excluded (unlike current behavior per [#9436]). - ### Integration Points -Apply `.gitignore`-parity matching in all chart file operations: +The new `.gitignore`-parity matching should apply in all existing chart file operations (unchanged scope): - `helm package` - `helm lint` @@ -133,6 +127,8 @@ Apply `.gitignore`-parity matching in all chart file operations: - `helm install` / `helm upgrade` (for local charts) - `.Files.Get` / `.Files.Glob` (file access in templates) +This list is representative; the matching logic applies wherever chart files are loaded or accessed. + ### Gating - **Charts v3 (`apiVersion: v3`)**: New `.gitignore`-parity semantics @@ -156,12 +152,6 @@ Charts opting into v3 accept new `.helmignore` semantics. Potential breaking cha | Trailing spaces stripped | Preserved with `\ ` | Unlikely to affect real charts | | No escape sequences | `\#`, `\!`, `\ ` supported | No breakage (feature addition) | -### Migration Guidance - -1. **Test with v3**: Before changing `apiVersion`, test charts with new semantics -2. **Review negation patterns**: Patterns with `!` may now work as originally intended -3. **Simplify patterns**: `**` globs can replace verbose directory-specific patterns - ## Security Implications None. This change only affects which local files are considered during chart operations. It does not: @@ -177,7 +167,7 @@ None. This change only affects which local files are considered during chart ope 1. **Primary statement**: "Charts v3 `.helmignore` uses identical pattern rules to `.gitignore`." -2. **Link to Git documentation**: Reference [git-scm.com/docs/gitignore][git-gitignore] as the canonical spec. +2. **Link to Git documentation**: Reference [git-scm.com/docs/gitignore][git-gitignore] as background documentation for the pattern semantics that `.helmignore` follows. 3. **Migration guide**: Document behavior differences between v2 and v3. @@ -188,6 +178,8 @@ None. This change only affects which local files are considered during chart ope 5. **Improve v2 and v3 documentation**: Existing `.helmignore` documentation is insufficient, leading to end user confusion, so this should be documented as well. +6. **File location**: Clarify that `.helmignore` must be in the chart root directory. Unlike `.gitignore`, nested `.helmignore` files are not loaded. This existing behavior is unchanged. + ### Release Notes - Highlight UX improvement for users expecting `.gitignore` behavior @@ -265,11 +257,22 @@ Rejected because partial fixes would leave confusing inconsistencies. Users expe ### Change behavior for all chart versions -Rejected because it would break existing charts that depend on current (albeit buggy) semantics. Charts v3 provides clean isolation for breaking changes. +Rejected because it would break existing charts that depend on current (albeit surprising) semantics. Charts v3 provides clean isolation for breaking changes. ## Open Issues -None. +### Subchart .helmignore Handling + +Should `.helmignore` files in subchart directories (`charts/*/`) be respected when processing an umbrella chart? + +**Current behavior**: Only the parent chart's `.helmignore` is loaded; subchart `.helmignore` files are ignored. + +**Open question**: Is this intended behavior, a bug, or an oversight? Arguments exist both ways: + +- **For respecting**: Chart authors expect their ignore rules to apply +- **Against (or: may not matter)**: Parent chart may want control; also, helm-ignored files would already be excluded when the subchart was packaged, so they likely won't be present anyway + +**Action**: Investigate history (git commits, meeting notes, previous maintainers) and discuss with community before deciding whether to change this behavior. For now, this HIP preserves existing behavior. ## References From 541faf0023f9fcf161447f57dfe153b74fe0d292 Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 26 Jan 2026 18:41:52 -0500 Subject: [PATCH 5/7] Add helm create task to how to teach this. Remove semi-related out of scope item Signed-off-by: Scott Rigby --- hips/hip-9999.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index deb3c5d5..bdea8fe5 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -180,6 +180,10 @@ None. This change only affects which local files are considered during chart ope 6. **File location**: Clarify that `.helmignore` must be in the chart root directory. Unlike `.gitignore`, nested `.helmignore` files are not loaded. This existing behavior is unchanged. +### Scaffold Update + +Update the default `.helmignore` generated by `helm create` for Charts v3. The current scaffold has been largely unchanged since 2016 ([helm#1028][#1028]). The v3 scaffold should demonstrate gitignore-parity patterns (e.g., `**` globs, whitelist patterns with `!`). + ### Release Notes - Highlight UX improvement for users expecting `.gitignore` behavior @@ -306,7 +310,6 @@ These issues concern _when_ `.helmignore` applies, not pattern syntax. Included ### Feature Requests (Out of Scope) - [#1674][#1674], [#5675][#5675] — Global `~/.helmignore` support. Already partially implemented; could adopt gitignore parity separately. -- [#989][#989] — Default patterns for editor swap files. Addressed previously; shows user expectation of sensible defaults. ### Documentation Issues @@ -336,7 +339,7 @@ These show user confusion that better docs (and gitignore parity) would reduce: [#10764]: https://github.com/helm/helm/issues/10764 [#1674]: https://github.com/helm/helm/issues/1674 [#5675]: https://github.com/helm/helm/issues/5675 -[#989]: https://github.com/helm/helm/issues/989 +[#1028]: https://github.com/helm/helm/pull/1028 [#4638]: https://github.com/helm/helm/issues/4638 [#12265]: https://github.com/helm/helm/pull/12265 [helm-www#1171]: https://github.com/helm/helm-www/issues/1171 From 6c4221db2640a33159f1eeb6e42c5a2221a26dcd Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 26 Jan 2026 19:06:27 -0500 Subject: [PATCH 6/7] remove empty optional fields from HIP frontmatter Signed-off-by: Scott Rigby --- hips/hip-9999.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index bdea8fe5..1275fb49 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -6,8 +6,6 @@ created: "2025-12-14" type: "feature" status: "draft" requires: ["HIP-0020"] -replaces: -superseded-by: --- ## Abstract From 580d4f2f3444ee8fe9562601ec789a753ee4238b Mon Sep 17 00:00:00 2001 From: Scott Rigby Date: Mon, 26 Jan 2026 23:27:27 -0500 Subject: [PATCH 7/7] Add reference implementation to HIP-9999 Link to proof-of-concept at github.com/scottrigby/helmignore-ref which validates go-git's gitignore library as the recommended implementation approach. Update implementation plan to reference go-git directly and add library to references section. Signed-off-by: Scott Rigby --- hips/hip-9999.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/hips/hip-9999.md b/hips/hip-9999.md index 1275fb49..9e1e9fed 100644 --- a/hips/hip-9999.md +++ b/hips/hip-9999.md @@ -230,18 +230,15 @@ node_modules/ ## Reference Implementation +A proof-of-concept is available at [github.com/scottrigby/helmignore-ref][helmignore-ref], demonstrating that `go-git/go-git/v5/plumbing/format/gitignore` meets all HIP requirements with minimal wrapper code (~76 lines). The repository includes research documentation comparing library options. + Implementation will be gated behind Charts v3 as specified in [HIP-0020][hip-0020]: -1. New matcher package under `internal/chart/v3/ignore/` implementing `.gitignore` semantics +1. New matcher package under `internal/chart/v3/ignore/` using go-git's gitignore library 2. Integration with v3 chart loader -3. Comprehensive test suite covering: - - All pattern types from Git documentation - - Edge cases from reported issues ([#8688], [#3622], [#1776]) - - Cross-platform path handling +3. Test suite covering all pattern types from this specification 4. Migration tests validating v2 charts remain unchanged -5. Update `helm create` scaffold for v3 charts (once [PR #31592][pr-31592] merges) to generate a `.helmignore` demonstrating gitignore-parity patterns - -Implementation details (library choice, architecture) are intentionally left to implementers. A separate implementation research document will evaluate options including existing Go libraries and FluxCD's `.sourceignore` implementation. +5. Update `helm create` scaffold for v3 charts (once [PR #31592][pr-31592] merges) ## Rejected Ideas @@ -286,6 +283,10 @@ Should `.helmignore` files in subchart directories (`charts/*/`) be respected wh - [git-scm.com/docs/gitignore][git-gitignore] +### Libraries + +- [go-git/go-git gitignore][go-git-gitignore] — Recommended implementation library + ### Issues Directly Addressed by This HIP These issues are resolved by implementing `.gitignore` pattern matching parity: @@ -325,8 +326,10 @@ These show user confusion that better docs (and gitignore parity) would reduce: [hip-0020]: https://github.com/helm/community/blob/main/hips/hip-0020.md +[helmignore-ref]: https://github.com/scottrigby/helmignore-ref [pr-31592]: https://github.com/helm/helm/pull/31592 [git-gitignore]: https://git-scm.com/docs/gitignore +[go-git-gitignore]: https://github.com/go-git/go-git/tree/main/plumbing/format/gitignore [#8688]: https://github.com/helm/helm/issues/8688 [#3622]: https://github.com/helm/helm/issues/3622 [#1776]: https://github.com/helm/helm/issues/1776