hooks
The rs hooks command installs, updates, and removes repository-level Git hooks. Hook scripts run in the project that installed them.
Usage
Run rs hooks without a subcommand to install or update hooks.
rs setup is an alias for rs hooks.
Install hooks
By default, hook scripts are stored in .rstack/hooks at the Git repository root. If the current directory is outside a Git repository, the command skips installation.
Add rs hooks to the prepare script of the project that owns the repository hooks:
Run the script once to install the hooks:
For example, create a pre-commit hook that runs rs staged:
You can safely run the installation more than once, and it does not load rstack.config.*. Run rs hooks again after cloning the repository or if the generated hook files are missing.
rs hooks updates the repository's core.hooksPath. If it detects another hooks path or existing Git hooks, it skips installation. Run rs hooks --force to let Rstack manage hooks instead.
Install options
--force
--force (or -f) installs Rstack hooks even when another Git hook setup already exists:
Rstack keeps the existing hook files and points core.hooksPath to its generated hooks directory. While this setting is active, Git does not run hooks from the previous location.
--force cannot replace hooks owned by another Rstack project.
Run rs hooks --force only once. Use rs hooks without --force in the prepare script.
--hooks-dir
Specifies a custom directory for hook scripts, relative to the Git repository root.
When using a custom directory, add the full command to the prepare script of the project that manages hooks:
The path must not contain
... This prevents hook files from being created or overwritten outside the repository through a parent directory path.
--help
--help (or -h) displays the command's usage, subcommands, and installation options.
Uninstall hooks
Run the command from the project that installed the hooks:
Rstack automatically finds the active hooks and removes the core.hooksPath setting and the generated _ directory. It does not delete project hook files such as .rstack/hooks/pre-commit. Hooks managed by another project or tool are left untouched.
Remove rs hooks from the prepare script if you do not want the hooks to be installed again.
If --force previously took over hooks in .git/hooks, those hooks become active again after uninstalling.
Hook files
The default directory structure is:
Files alongside _ are repository hook scripts. The _ directory contains generated files and is ignored by Git. rs hooks points core.hooksPath to .rstack/hooks/_.
Supported hooks
Rstack CLI supports these client-side Git hooks:
pre-commitpre-merge-commitprepare-commit-msgcommit-msgpost-commitapplypatch-msgpre-applypatchpost-applypatchpre-rebasepost-rewritepost-checkoutpost-mergepre-pushpre-auto-gc
Create a file with the matching name alongside the _ directory.
Hook runtime
Rstack CLI runs hook scripts with POSIX sh -e. It forwards Git's arguments and standard input, then returns the hook's exit code. Before running a hook, Rstack changes to the project that installed the hooks and prepends that project's node_modules/.bin to PATH.
Disable and debug
Set RSTACK_HOOKS=0 to skip installation or hook execution:
Set RSTACK_HOOKS=2 to trace the Rstack CLI hook runtime, including how it invokes the hook script and handles its exit code; to trace commands inside the hook script, add set -x to the script:
Configure the hook environment
Before running a hook script, Rstack CLI loads this optional POSIX shell file:
Use it to initialize a Node.js version manager, update PATH, or set RSTACK_HOOKS=0 for the current user.
Ownership safety
Each generated hooks directory records its owning project. Only that project should include rs hooks in its prepare script. Rstack skips installation from any other project, even with --force, and refuses to remove hooks owned by another project.
To transfer ownership:
- Remove
rs hooksfrom the previous owner'spreparescript. - Run
rs hooks uninstallfrom the previous owner. - Add
rs hooksto the new owner'spreparescript and run it once.
Monorepo
In a monorepo, the project that provides Rstack CLI may live in a subdirectory such as frontend/. Running rs hooks there still installs hooks at the Git repository root:
Rstack records frontend as the owning project. The hook scripts stay at the repository root but run from frontend, allowing them to use its configuration and dependencies without an explicit cd:
Worktree behavior
Rstack preserves the Git configuration scope of the active core.hooksPath. If a linked worktree uses a worktree-scoped hooks path, rs hooks --force replaces it in that scope instead of writing a local setting that Git would ignore.
rs hooks uninstall also removes the setting from that scope. Removing a worktree-scoped installation affects only the current worktree and leaves hooks in other linked checkouts unchanged. A local core.hooksPath setting is shared across linked checkouts, so changing or removing it affects every checkout that does not override it.
Troubleshooting
Hook does not run
- Check that the hook script has a supported name and is next to the
_directory. - Run
git config --show-scope --get core.hooksPathand verify the effective scope and path. - Rerun
rs hooksto restore generated files and executable permissions. - Check that
RSTACK_HOOKSis not set to0in the environment or initialization file. - If another hook setup is detected, run
rs hooks --force. - If another project is reported as the hooks owner, follow the steps in Ownership safety.
Hook scripts do not need to be executable because Rstack CLI runs them with sh.
Command not found
For exit code 127, Rstack CLI prints the effective PATH. If a GUI Git client cannot find Node.js or the package manager, initialize them in hooks-init.sh.
Windows and Yarn
On Windows, hooks run in the POSIX shell included with Git for Windows. Use LF line endings and / path separators in hooks.
Yarn PnP does not provide node_modules/.bin. Run tools through a Yarn script, such as yarn run test, and make Node.js and Yarn available through hooks-init.sh when needed.