From a96a2835a4096b1c673d83f2be8575e1f756b101 Mon Sep 17 00:00:00 2001 From: Yurii Polishchuk Date: Wed, 10 Jun 2026 13:33:50 +0200 Subject: [PATCH 1/8] fix: scrub GIT_* env vars in hooks that shell to git clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hooks that invoke `tofu init` / `terraform init` (terraform_validate, terraform_tflint, terraform_docs) end up running `git clone ` under the hood for each registry/git-source module. When the operator's `git commit` runs from a linked worktree, the parent git sets GIT_INDEX_FILE (pointing at `.git/worktrees//index`) in the hook subprocess env. The child `git clone` inherits this and writes the cloned module's blob OIDs into the parent worktree's index. The next `git commit` then fails at tree-build: error: invalid object 100644 for '' error: Error building trees Reproduction: git init && git commit --allow-empty -m init mkdir stack cat > stack/main.tf <<'TF' module "test" { source = "terraform-aws-modules/iam/aws" version = "5.x" } TF cat > .pre-commit-config.yaml <<'YAML' repos: - repo: https://github.com/antonbabenko/pre-commit-terraform rev: v1.106.0 hooks: - id: terraform_validate args: - --hook-config=--retry-once-with-cleanup=true - --tf-init-args=-backend=false YAML git add -A && git commit -m baseline git worktree add ../wt && cd ../wt pre-commit install echo "" >> stack/main.tf git add stack/main.tf git commit -m test # fails with 'Error building trees' git fsck --no-progress # invalid sha1 pointer in cache-tree Other GIT_* vars (GIT_DIR, GIT_WORK_TREE, GIT_OBJECT_DIRECTORY) are overridden by `git clone`'s own target-dir setup; only GIT_INDEX_FILE slips through. Scrubbing all four matches the four documented offenders in pre-commit framework's own `no_git_env` helper (`pre_commit/git.py:20-38`), which explicitly states: # GIT_DIR: Causes git clone to clone wrong thing # GIT_INDEX_FILE: Causes 'error invalid object ...' during commit pre-commit framework deliberately does NOT scrub GIT_* from user hook subprocesses (only its own internal git calls) per the maintainer in pre-commit/pre-commit#1849: "they need the same code as in our no_git_env helper if they are dealing with doing git writes". This patch applies that recommendation in pre-commit-terraform's hooks that perform git writes via `tofu init` / `terraform init`. Verified by reproducing the failure on v1.106.0 from a worktree with a module-using stack, then confirming the fix removes both the index pollution and the tree-build error. SSH/TLS/config-related GIT_* env vars are preserved (only the four documented "dangerous" ones are unset) so SSH-source modules authenticate normally. Net change: one new helper `common::scrub_git_env` in _common.sh, called once from `main()` of each affected hook. Zero behavior change for non-worktree users — their GIT_INDEX_FILE is empty for these hooks so the unset is a no-op. Refs: #992 --- hooks/_common.sh | 32 ++++++++++++++++++++++++++++++++ hooks/terraform_docs.sh | 1 + hooks/terraform_tflint.sh | 1 + hooks/terraform_validate.sh | 1 + 4 files changed, 35 insertions(+) diff --git a/hooks/_common.sh b/hooks/_common.sh index fd26dfce1..97d85fc00 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -116,6 +116,38 @@ function common::parse_cmdline { done } +####################################################################### +# Scrub GIT_* environment variables that get inherited from `git commit` +# and corrupt child `git clone` operations spawned by `tofu init` / +# `terraform init` when fetching modules. +# +# Without this, a `git commit` from a git worktree fails at tree-build: +# error: invalid object 100644 for '' +# error: Error building trees +# +# Root cause: the child `git clone` inherits `GIT_INDEX_FILE` (pointing +# at the worktree's index) from the parent `git commit` env. Most +# clone-side env vars (`GIT_DIR`, `GIT_WORK_TREE`, `GIT_OBJECT_DIRECTORY`) +# are overridden by `git clone`'s own target-dir setup; only +# `GIT_INDEX_FILE` is not, so the clone writes the cloned module's blob +# OIDs into the parent worktree's index. The next `git commit` then +# cannot resolve those OIDs in the parent's object DB. +# +# pre-commit framework deliberately does NOT scrub GIT_* for user hooks +# (only its own internal git calls) per the maintainer's stance in +# pre-commit/pre-commit#1849: "they need the same code as in our +# no_git_env helper if they are dealing with doing git writes". The +# `no_git_env` helper (pre_commit/git.py:20-38) explicitly documents +# `GIT_INDEX_FILE: Causes 'error invalid object ...' during commit` +# and `GIT_DIR: Causes git clone to clone wrong thing` — we scrub both +# (and the two other documented offenders) defensively even though +# `GIT_INDEX_FILE` is the proximate cause of the bug class observed in +# pre-commit-terraform hooks. +####################################################################### +function common::scrub_git_env { + unset GIT_INDEX_FILE GIT_DIR GIT_WORK_TREE GIT_OBJECT_DIRECTORY +} + ####################################################################### # Expand environment variables definition into their values in '--args'. # Support expansion only for ${ENV_VAR} vars, not $ENV_VAR. diff --git a/hooks/terraform_docs.sh b/hooks/terraform_docs.sh index 7644b5e4c..1e5dcc6cf 100755 --- a/hooks/terraform_docs.sh +++ b/hooks/terraform_docs.sh @@ -20,6 +20,7 @@ function main { common::parse_cmdline "$@" common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars + common::scrub_git_env # Support for setting relative PATH to .terraform-docs.yml config. for i in "${!ARGS[@]}"; do ARGS[i]=${ARGS[i]/--config=/--config=$(pwd)\/} diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index 1c2439f0f..0eaf75196 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -13,6 +13,7 @@ function main { common::parse_cmdline "$@" common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars + common::scrub_git_env # JFYI: tflint color already suppressed via PRE_COMMIT_COLOR=never diff --git a/hooks/terraform_validate.sh b/hooks/terraform_validate.sh index ad792b038..24e9069e4 100755 --- a/hooks/terraform_validate.sh +++ b/hooks/terraform_validate.sh @@ -15,6 +15,7 @@ function main { common::parse_cmdline "$@" common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars + common::scrub_git_env # Suppress terraform validate color if [ "$PRE_COMMIT_COLOR" = "never" ]; then From 211d9cc8f828fe339422474007ffb551f7ff6576 Mon Sep 17 00:00:00 2001 From: Yurii Polishchuk Date: Wed, 10 Jun 2026 14:09:14 +0200 Subject: [PATCH 2/8] docs(scrub_git_env): clarify targeted-subset vs no_git_env allowlist Address CodeRabbit feedback on PR #993: the previous docstring read as though common::scrub_git_env mirrored pre-commit's no_git_env helper. It does not. no_git_env is allowlist-based: it scrubs all GIT_* except a whitelist of ~11 known-safe vars (GIT_EXEC_PATH, GIT_SSH, GIT_SSH_COMMAND, GIT_ASKPASS, GIT_SSL_*, GIT_CONFIG_KEY_*, GIT_CONFIG_VALUE_*, GIT_CONFIG_COUNT, GIT_HTTP_PROXY_AUTHMETHOD, GIT_ALLOW_PROTOCOL) and runs only on pre-commit's internal git calls. common::scrub_git_env is denylist-based: it unsets only four specific vars that pre_commit/git.py:20-38 documents as dangerous when leaked into child git (GIT_INDEX_FILE, GIT_DIR, GIT_WORK_TREE, GIT_OBJECT_DIRECTORY), and runs in user hook subprocesses. New docstring spells this out, explains why each of the four is included, and notes why we chose a denylist over an allowlist mirror (bash portability, observed bug fix scope, lower blast radius for hook authors with custom registry/proxy env vars). --- hooks/_common.sh | 56 ++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index 97d85fc00..5b91f6bab 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -117,32 +117,46 @@ function common::parse_cmdline { } ####################################################################### -# Scrub GIT_* environment variables that get inherited from `git commit` -# and corrupt child `git clone` operations spawned by `tofu init` / -# `terraform init` when fetching modules. +# Scrub four dangerous GIT_* env vars before child git operations. +# +# Without this, `git commit` from a linked git worktree fails at +# tree-build when a hook runs `tofu init` / `terraform init` (which +# spawns `git clone` for each module source): # -# Without this, a `git commit` from a git worktree fails at tree-build: # error: invalid object 100644 for '' # error: Error building trees # -# Root cause: the child `git clone` inherits `GIT_INDEX_FILE` (pointing -# at the worktree's index) from the parent `git commit` env. Most -# clone-side env vars (`GIT_DIR`, `GIT_WORK_TREE`, `GIT_OBJECT_DIRECTORY`) -# are overridden by `git clone`'s own target-dir setup; only -# `GIT_INDEX_FILE` is not, so the clone writes the cloned module's blob -# OIDs into the parent worktree's index. The next `git commit` then -# cannot resolve those OIDs in the parent's object DB. +# Root cause: the child `git clone` inherits GIT_INDEX_FILE from the +# parent `git commit` env (pointing at the worktree's index), then +# writes the cloned module's blob OIDs into the parent worktree's +# index. The subsequent commit cannot resolve those OIDs. +# +# Targeted denylist, NOT a mirror of pre-commit's `no_git_env`: +# `no_git_env` (pre_commit/git.py) uses an ALLOWLIST that scrubs all +# GIT_* except ~11 known-safe vars (GIT_EXEC_PATH, GIT_SSH, +# GIT_SSH_COMMAND, GIT_ASKPASS, GIT_SSL_CAINFO, GIT_SSL_NO_VERIFY, +# GIT_CONFIG_KEY_*, GIT_CONFIG_VALUE_*, GIT_CONFIG_COUNT, +# GIT_HTTP_PROXY_AUTHMETHOD, GIT_ALLOW_PROTOCOL). It runs only on +# pre-commit's INTERNAL git calls, not on user hook subprocesses +# (per pre-commit/pre-commit#1849). +# +# We unset only the four vars that pre-commit's own docstring (git.py +# lines 20-38) names as dangerous when leaked into child git: +# +# GIT_INDEX_FILE proximate cause; "Causes 'error invalid +# object ...' during commit" in git.py. +# GIT_DIR "Causes git clone to clone wrong thing". +# GIT_WORK_TREE defensive; paired with GIT_DIR. +# GIT_OBJECT_DIRECTORY defensive; prevents child writes into the +# parent object DB via non-clone git calls. # -# pre-commit framework deliberately does NOT scrub GIT_* for user hooks -# (only its own internal git calls) per the maintainer's stance in -# pre-commit/pre-commit#1849: "they need the same code as in our -# no_git_env helper if they are dealing with doing git writes". The -# `no_git_env` helper (pre_commit/git.py:20-38) explicitly documents -# `GIT_INDEX_FILE: Causes 'error invalid object ...' during commit` -# and `GIT_DIR: Causes git clone to clone wrong thing` — we scrub both -# (and the two other documented offenders) defensively even though -# `GIT_INDEX_FILE` is the proximate cause of the bug class observed in -# pre-commit-terraform hooks. +# Denylist over allowlist mirror because: +# 1. Bash equivalent of the Python whitelist scan is ~15-20 lines +# versus a one-line `unset`. +# 2. The observed bug is fully fixed by scrubbing GIT_INDEX_FILE +# alone; the other three are belt-and-braces. +# 3. Narrower scrub minimizes risk of breaking hook authors who +# rely on inheritance of vars an aggressive allowlist might drop. ####################################################################### function common::scrub_git_env { unset GIT_INDEX_FILE GIT_DIR GIT_WORK_TREE GIT_OBJECT_DIRECTORY From 63ab2bcd0f3cac61d8f4413021b623cb45743d4d Mon Sep 17 00:00:00 2001 From: Yurii Polishchuk Date: Thu, 11 Jun 2026 19:20:42 +0200 Subject: [PATCH 3/8] fix: Scope scrub to terraform_validate only; address review wording Per review on PR #993: - MaxymVlasov could not reproduce the worktree bug in terraform_tflint or terraform_docs (terraform-docs does not run init), so the common::scrub_git_env calls are removed from both. The confirmed reproduction path is terraform_validate -> tofu/terraform init -> git clone, which keeps its call. - Docstring reworded per yermulnik: drop 'dangerous' (the vars are incompatible with pre-commit's hook env, not dangerous), drop the var count, capitalize Git as a proper name, use full clickable URLs instead of repo-relative paths and issue shorthand, drop line-range references that rot as upstream moves. - GIT_OBJECT_DIRECTORY provenance corrected: it is not named in pre-commit's no_git_env docstring; it comes from Git's own repository-location environment variables (man 1 git). The docstring now cites that source for all four vars. - unset arguments alphabetized. --- hooks/_common.sh | 48 ++++++++++++++++----------------------- hooks/terraform_docs.sh | 1 - hooks/terraform_tflint.sh | 1 - 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index 5b91f6bab..cd227eda5 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -117,11 +117,11 @@ function common::parse_cmdline { } ####################################################################### -# Scrub four dangerous GIT_* env vars before child git operations. +# Scrub some GIT_* env vars before child Git operations. # -# Without this, `git commit` from a linked git worktree fails at +# Without this, `git commit` from a linked Git worktree fails at # tree-build when a hook runs `tofu init` / `terraform init` (which -# spawns `git clone` for each module source): +# spawns `git clone` for each Git-sourced module): # # error: invalid object 100644 for '' # error: Error building trees @@ -131,35 +131,27 @@ function common::parse_cmdline { # writes the cloned module's blob OIDs into the parent worktree's # index. The subsequent commit cannot resolve those OIDs. # -# Targeted denylist, NOT a mirror of pre-commit's `no_git_env`: -# `no_git_env` (pre_commit/git.py) uses an ALLOWLIST that scrubs all -# GIT_* except ~11 known-safe vars (GIT_EXEC_PATH, GIT_SSH, -# GIT_SSH_COMMAND, GIT_ASKPASS, GIT_SSL_CAINFO, GIT_SSL_NO_VERIFY, -# GIT_CONFIG_KEY_*, GIT_CONFIG_VALUE_*, GIT_CONFIG_COUNT, -# GIT_HTTP_PROXY_AUTHMETHOD, GIT_ALLOW_PROTOCOL). It runs only on -# pre-commit's INTERNAL git calls, not on user hook subprocesses -# (per pre-commit/pre-commit#1849). +# pre-commit scrubs GIT_* only for its own internal Git calls, not +# for hook subprocesses - hook authors are expected to handle it +# themselves: https://github.com/pre-commit/pre-commit/issues/1849 # -# We unset only the four vars that pre-commit's own docstring (git.py -# lines 20-38) names as dangerous when leaked into child git: +# This is a targeted denylist, NOT a mirror of pre-commit's +# allowlist-based `no_git_env` helper +# (https://github.com/pre-commit/pre-commit/blob/main/pre_commit/git.py), +# which drops all GIT_* except known-safe vars (GIT_ASKPASS, +# GIT_CONFIG_*, GIT_SSH, GIT_SSH_COMMAND, GIT_SSL_*, etc.). We unset +# only the vars that leak the parent repository's location into child +# Git processes (see "Environment Variables" in `man 1 git`, +# https://git-scm.com/docs/git#_environment_variables): # -# GIT_INDEX_FILE proximate cause; "Causes 'error invalid -# object ...' during commit" in git.py. -# GIT_DIR "Causes git clone to clone wrong thing". -# GIT_WORK_TREE defensive; paired with GIT_DIR. -# GIT_OBJECT_DIRECTORY defensive; prevents child writes into the -# parent object DB via non-clone git calls. -# -# Denylist over allowlist mirror because: -# 1. Bash equivalent of the Python whitelist scan is ~15-20 lines -# versus a one-line `unset`. -# 2. The observed bug is fully fixed by scrubbing GIT_INDEX_FILE -# alone; the other three are belt-and-braces. -# 3. Narrower scrub minimizes risk of breaking hook authors who -# rely on inheritance of vars an aggressive allowlist might drop. +# GIT_DIR makes child Git operate on the parent repo +# GIT_INDEX_FILE proximate cause of the failure above +# GIT_OBJECT_DIRECTORY redirects child object writes into the +# parent object database +# GIT_WORK_TREE pairs with GIT_DIR ####################################################################### function common::scrub_git_env { - unset GIT_INDEX_FILE GIT_DIR GIT_WORK_TREE GIT_OBJECT_DIRECTORY + unset GIT_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_WORK_TREE } ####################################################################### diff --git a/hooks/terraform_docs.sh b/hooks/terraform_docs.sh index 1e5dcc6cf..7644b5e4c 100755 --- a/hooks/terraform_docs.sh +++ b/hooks/terraform_docs.sh @@ -20,7 +20,6 @@ function main { common::parse_cmdline "$@" common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars - common::scrub_git_env # Support for setting relative PATH to .terraform-docs.yml config. for i in "${!ARGS[@]}"; do ARGS[i]=${ARGS[i]/--config=/--config=$(pwd)\/} diff --git a/hooks/terraform_tflint.sh b/hooks/terraform_tflint.sh index 0eaf75196..1c2439f0f 100755 --- a/hooks/terraform_tflint.sh +++ b/hooks/terraform_tflint.sh @@ -13,7 +13,6 @@ function main { common::parse_cmdline "$@" common::export_provided_env_vars "${ENV_VARS[@]}" common::parse_and_export_env_vars - common::scrub_git_env # JFYI: tflint color already suppressed via PRE_COMMIT_COLOR=never From 9c438a2c31c82b66666d52c144af34d734adb591 Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Thu, 18 Jun 2026 17:47:13 +0300 Subject: [PATCH 4/8] docs(scrub_git_env): trim docstring; move bug narrative to commit Failure scenario, root-cause deep-dive, and no_git_env allowlist enumeration belong in git history, not in source. Keep only: - what the function does and why each var is included - the pre-commit framework design constraint + issue link - the denylist-vs-allowlist note Assisted-by: Sisyphus:claude-sonnet-4-6 opencode --- hooks/_common.sh | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index cd227eda5..29bdee671 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -117,32 +117,16 @@ function common::parse_cmdline { } ####################################################################### -# Scrub some GIT_* env vars before child Git operations. +# Scrub GIT_* vars that leak the parent repo location into child Git +# processes (see https://git-scm.com/docs/git#_environment_variables). # -# Without this, `git commit` from a linked Git worktree fails at -# tree-build when a hook runs `tofu init` / `terraform init` (which -# spawns `git clone` for each Git-sourced module): -# -# error: invalid object 100644 for '' -# error: Error building trees -# -# Root cause: the child `git clone` inherits GIT_INDEX_FILE from the -# parent `git commit` env (pointing at the worktree's index), then -# writes the cloned module's blob OIDs into the parent worktree's -# index. The subsequent commit cannot resolve those OIDs. -# -# pre-commit scrubs GIT_* only for its own internal Git calls, not -# for hook subprocesses - hook authors are expected to handle it -# themselves: https://github.com/pre-commit/pre-commit/issues/1849 +# pre-commit scrubs GIT_* only for its own internal Git calls, not for +# hook subprocesses - hook authors must handle it themselves: +# https://github.com/pre-commit/pre-commit/issues/1849 # # This is a targeted denylist, NOT a mirror of pre-commit's -# allowlist-based `no_git_env` helper -# (https://github.com/pre-commit/pre-commit/blob/main/pre_commit/git.py), -# which drops all GIT_* except known-safe vars (GIT_ASKPASS, -# GIT_CONFIG_*, GIT_SSH, GIT_SSH_COMMAND, GIT_SSL_*, etc.). We unset -# only the vars that leak the parent repository's location into child -# Git processes (see "Environment Variables" in `man 1 git`, -# https://git-scm.com/docs/git#_environment_variables): +# allowlist-based no_git_env helper. We unset only the vars that leak +# the parent repository's location into child Git processes: # # GIT_DIR makes child Git operate on the parent repo # GIT_INDEX_FILE proximate cause of the failure above From 6aa3c54803ac1487d34d314dd991eab8c7ffd702 Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Thu, 18 Jun 2026 17:55:18 +0300 Subject: [PATCH 5/8] docs(scrub_git_env): mention linked worktree as the trigger Assisted-by: Sisyphus:claude-sonnet-4-6 opencode --- hooks/_common.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index 29bdee671..532846288 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -117,8 +117,9 @@ function common::parse_cmdline { } ####################################################################### -# Scrub GIT_* vars that leak the parent repo location into child Git -# processes (see https://git-scm.com/docs/git#_environment_variables). +# Scrub GIT_* vars inherited from a linked Git worktree that would +# leak the parent repo location into child Git processes +# (see https://git-scm.com/docs/git#_environment_variables). # # pre-commit scrubs GIT_* only for its own internal Git calls, not for # hook subprocesses - hook authors must handle it themselves: From a8a98ab6a90e4db6cb2339cf583559c2701386c7 Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Thu, 18 Jun 2026 18:26:12 +0300 Subject: [PATCH 6/8] refactor(scrub_git_env): loop over readonly array; tolerate readonly vars Assisted-by: Sisyphus:claude-sonnet-4-6 opencode --- hooks/_common.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index 532846288..a8a6339a0 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -136,7 +136,16 @@ function common::parse_cmdline { # GIT_WORK_TREE pairs with GIT_DIR ####################################################################### function common::scrub_git_env { - unset GIT_DIR GIT_INDEX_FILE GIT_OBJECT_DIRECTORY GIT_WORK_TREE + local -r git_env_vars=( + GIT_DIR + GIT_INDEX_FILE + GIT_OBJECT_DIRECTORY + GIT_WORK_TREE + ) + local env_var + for env_var in "${git_env_vars[@]}"; do + unset "$env_var" 2> /dev/null || true + done } ####################################################################### From 8d02f626fe42059391f4fa75d4a3353e88581aa9 Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Thu, 18 Jun 2026 18:37:08 +0300 Subject: [PATCH 7/8] refactor(scrub_git_env): simplify to unset -v; keep || true for resilience Assisted-by: Sisyphus:claude-sonnet-4-6 opencode --- hooks/_common.sh | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index a8a6339a0..af0d5c32e 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -136,16 +136,12 @@ function common::parse_cmdline { # GIT_WORK_TREE pairs with GIT_DIR ####################################################################### function common::scrub_git_env { - local -r git_env_vars=( - GIT_DIR - GIT_INDEX_FILE - GIT_OBJECT_DIRECTORY - GIT_WORK_TREE - ) - local env_var - for env_var in "${git_env_vars[@]}"; do - unset "$env_var" 2> /dev/null || true - done + unset -v \ + GIT_DIR \ + GIT_INDEX_FILE \ + GIT_OBJECT_DIRECTORY \ + GIT_WORK_TREE || + true } ####################################################################### From 993f492481da9f36e2c3dc10520baac0623c43b4 Mon Sep 17 00:00:00 2001 From: MaxymVlasov Date: Thu, 18 Jun 2026 18:39:20 +0300 Subject: [PATCH 8/8] refactor(scrub_git_env): use readonly array with unset -v Assisted-by: Sisyphus:claude-sonnet-4-6 opencode --- hooks/_common.sh | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/hooks/_common.sh b/hooks/_common.sh index af0d5c32e..e59a22b95 100644 --- a/hooks/_common.sh +++ b/hooks/_common.sh @@ -136,12 +136,13 @@ function common::parse_cmdline { # GIT_WORK_TREE pairs with GIT_DIR ####################################################################### function common::scrub_git_env { - unset -v \ - GIT_DIR \ - GIT_INDEX_FILE \ - GIT_OBJECT_DIRECTORY \ - GIT_WORK_TREE || - true + local -ra git_env_vars=( + GIT_DIR + GIT_INDEX_FILE + GIT_OBJECT_DIRECTORY + GIT_WORK_TREE + ) + unset -v "${git_env_vars[@]}" || true } #######################################################################