You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add a way to scope a hook run to staged files only without
performing a git stash. Today the only way to get the
"staged files only" file list is to enable a stash method, which
mutates the working tree.
Motivation
In src/hook.rs::file_list(), the file-set decision is binary:
So "staged files only" is only reachable by also opting into stash_unstaged / pop_stash, which:
modifies the working tree mid-run,
requires capturing/restoring the index,
and can interact badly with editors, watchers, and other
concurrent tooling that observes the worktree.
Users who already trust their unstaged changes — or who run hk
outside a pre-commit gate (CI on a checked-out ref, scripted
fixers, IDE integrations) — want the scope without the mutation.
Reproduction
hk -v run pre-commit --fix --stash none -P
Today this runs over staged + unstaged + untracked files
(no stash, full file set). There is no invocation that combines
"no stash" with "staged files only" — the only way to get the
staged-only file list is to drop --stash none and accept the
worktree mutation.
Observed file-set difference
With --stash none (no stash, full scope — what you get today
when you want to avoid worktree mutation):
With --stash git (staged only, but mutates the worktree —
the only way to get staged-only scope today):
$ hk -v run pre-commit --fix --stash git -P
DEBUG $ git update-index -q --refresh
✔ Fetching staged files
DEBUG files: {"hk.pkl"}
Plan: pre-commit
Run type: fix
[parallel group] group_0
✓ pj-git-check (1 file matched)
✓ check-added-large-files (1 file matched)
○ prettier (no files matched filters)
○ ruff (no files matched filters)
○ tombi (no files matched filters)
○ tombi-format (no files matched filters)
○ biome (no files matched filters)
✓ pkl (1 file matched)
✓ pkl-format (1 file matched)
Only hk.pkl was actually staged; the other 20 files are
unstaged or untracked changes that --stash none pulls in.
The desired invocation would match --stash git's file set
(just hk.pkl) without touching the worktree.
Proposed behavior
Decouple the "narrow to staged" branch from the stash boolean.
Options, in rough order of preference:
New CLI flag: --staged (and matching HookOptions field)
that selects the staged-only file list, independent of --stash.
New StashMethod variant: StashMethod::None already
means "no stash, full file set." A StashMethod::ScopeOnly
(or similar name) could mean "no stash, staged-only scope."
Config-level option on Hook (e.g. scope = "staged")
mirroring the CLI flag for hooks where this should be the
default.
Whichever surface is chosen, the implementation is a small
change in file_list(): branch on the new flag before the
existing stash check.
Out of scope
Changing the default behavior of any existing hook.
Changing what stash does when enabled.
Workarounds today
hk check --files "$(git diff --cached --name-only)" — works
but loses hk's normal file discovery (untracked-but-staged
intent files, deletions, renames) and is awkward in hk.pkl-driven hook configs.
Per-step glob / condition filters — narrow what each step
sees but don't change the hook-level file list.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Summary
Add a way to scope a hook run to staged files only without
performing a
git stash. Today the only way to get the"staged files only" file list is to enable a stash method, which
mutates the working tree.
Motivation
In
src/hook.rs::file_list(), the file-set decision is binary:stashtruthy →git_status.staged_filesonly(src/hook.rs:1222-1224)
stashfalsy → staged + unstaged + untracked(src/hook.rs:1226-1234)
So "staged files only" is only reachable by also opting into
stash_unstaged/pop_stash, which:concurrent tooling that observes the worktree.
Users who already trust their unstaged changes — or who run hk
outside a pre-commit gate (CI on a checked-out ref, scripted
fixers, IDE integrations) — want the scope without the
mutation.
Reproduction
Today this runs over staged + unstaged + untracked files
(no stash, full file set). There is no invocation that combines
"no stash" with "staged files only" — the only way to get the
staged-only file list is to drop
--stash noneand accept theworktree mutation.
Observed file-set difference
With
--stash none(no stash, full scope — what you get todaywhen you want to avoid worktree mutation):
With
--stash git(staged only, but mutates the worktree —the only way to get staged-only scope today):
Only
hk.pklwas actually staged; the other 20 files areunstaged or untracked changes that
--stash nonepulls in.The desired invocation would match
--stash git's file set(just
hk.pkl) without touching the worktree.Proposed behavior
Decouple the "narrow to staged" branch from the stash boolean.
Options, in rough order of preference:
--staged(and matchingHookOptionsfield)that selects the staged-only file list, independent of
--stash.StashMethodvariant:StashMethod::Nonealreadymeans "no stash, full file set." A
StashMethod::ScopeOnly(or similar name) could mean "no stash, staged-only scope."
Hook(e.g.scope = "staged")mirroring the CLI flag for hooks where this should be the
default.
Whichever surface is chosen, the implementation is a small
change in
file_list(): branch on the new flag before theexisting
stashcheck.Out of scope
stashdoes when enabled.Workarounds today
hk check --files "$(git diff --cached --name-only)"— worksbut loses hk's normal file discovery (untracked-but-staged
intent files, deletions, renames) and is awkward in
hk.pkl-driven hook configs.glob/conditionfilters — narrow what each stepsees but don't change the hook-level file list.
All reactions