diff --git a/README.md b/README.md
index 6285e4c..7ef8120 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ It also covers local development needs outside Rstack's scope, with Prettier for
| [`rs check`](https://rstack.rs/guide/cli/check) | Run static checks, including lint and format |
| [`rs lib`](https://rstack.rs/guide/cli/lib) | Build library |
| [`rs doc`](https://rstack.rs/guide/cli/doc) | Serve or build docs |
-| [`rs setup`](https://rstack.rs/guide/cli/setup) | Install Git hooks |
+| [`rs hooks`](https://rstack.rs/guide/cli/hooks) | Manage Git hooks |
| [`rs staged`](https://rstack.rs/guide/cli/staged) | Run tasks on staged Git files |
Rstack CLI fits into your existing project workflow. It does not replace your runtime, package manager, or task runner, such as [pnpm](https://github.com/pnpm/pnpm), [Bun](https://github.com/oven-sh/bun), [Turborepo](https://github.com/vercel/turborepo), [Nx](https://github.com/nrwl/nx), and [Nub](https://github.com/nubjs/nub).
@@ -63,7 +63,7 @@ bun add -d rstack
"lib": "rs lib",
"doc": "rs doc",
"format": "rs fmt",
- "prepare": "rs setup"
+ "prepare": "rs hooks"
}
}
```
diff --git a/website/docs/en/guide/cli/_meta.json b/website/docs/en/guide/cli/_meta.json
index 5357606..c228ad7 100644
--- a/website/docs/en/guide/cli/_meta.json
+++ b/website/docs/en/guide/cli/_meta.json
@@ -8,6 +8,6 @@
"check",
"lint",
"fmt",
- "setup",
+ "hooks",
"staged"
]
diff --git a/website/docs/en/guide/cli/hooks.mdx b/website/docs/en/guide/cli/hooks.mdx
new file mode 100644
index 0000000..1011313
--- /dev/null
+++ b/website/docs/en/guide/cli/hooks.mdx
@@ -0,0 +1,247 @@
+---
+description: 'Install, configure, troubleshoot, and safely remove repository-level Git hooks with Rstack CLI.'
+---
+
+# hooks
+
+import { PackageManagerTabs } from '@rspress/core/theme';
+
+The `rs hooks` command installs, updates, and removes repository-level [Git hooks](https://git-scm.com/docs/githooks). Hook scripts run in the project that installed them.
+
+## Usage
+
+```bash
+rs hooks [options]
+rs hooks uninstall
+```
+
+Run `rs hooks` without a subcommand to install or update hooks.
+
+:::tip Alias
+`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:
+
+```json title="package.json"
+{
+ "scripts": {
+ "prepare": "rs hooks"
+ }
+}
+```
+
+Run the script once to install the hooks:
+
+
+
+For example, create a `pre-commit` hook that runs [`rs staged`](./staged):
+
+```sh title=".rstack/hooks/pre-commit"
+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.
+
+:::warning Existing Git hook managers
+
+`rs hooks` updates the repository's [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath). 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:
+
+```bash
+rs hooks --force
+```
+
+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.
+
+:::tip
+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.
+
+```bash
+rs hooks --hooks-dir config/git-hooks
+
+# Quote paths that contain spaces
+rs hooks --hooks-dir "config/git hooks"
+```
+
+When using a custom directory, add the full command to the `prepare` script of the project that manages hooks:
+
+```json title="package.json"
+{
+ "scripts": {
+ "prepare": "rs hooks --hooks-dir config/git-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.
+
+```bash
+rs hooks --help
+```
+
+## Uninstall hooks
+
+Run the command from the project that installed the hooks:
+
+```bash
+rs hooks uninstall
+```
+
+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:
+
+```text
+.rstack/
+└── hooks/
+ ├── pre-commit # Repository hook script: edit and commit
+ └── _/ # Generated by rs hooks; ignored by Git
+ ├── .gitignore
+ ├── .owner
+ ├── runner
+ ├── pre-commit
+ ├── commit-msg
+ └── ...
+```
+
+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-commit`
+- `pre-merge-commit`
+- `prepare-commit-msg`
+- `commit-msg`
+- `post-commit`
+- `applypatch-msg`
+- `pre-applypatch`
+- `post-applypatch`
+- `pre-rebase`
+- `post-rewrite`
+- `post-checkout`
+- `post-merge`
+- `pre-push`
+- `pre-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:
+
+```bash
+RSTACK_HOOKS=0 git commit -m "Skip hooks"
+```
+
+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:
+
+```bash
+RSTACK_HOOKS=2 git commit -m "Trace hooks"
+```
+
+### Configure the hook environment
+
+Before running a hook script, Rstack CLI loads this optional POSIX shell file:
+
+```text
+${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh
+```
+
+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:
+
+1. Remove `rs hooks` from the previous owner's `prepare` script.
+2. Run `rs hooks uninstall` from the previous owner.
+3. Add `rs hooks` to the new owner's `prepare` script 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:
+
+```text
+repo/.rstack/hooks/
+repo/.rstack/hooks/_/
+core.hooksPath=.rstack/hooks/_
+```
+
+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`:
+
+```sh title=".rstack/hooks/pre-commit"
+rs staged
+```
+
+## 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](#supported-hooks) and is next to the `_` directory.
+- Run `git config --show-scope --get core.hooksPath` and verify the effective scope and path.
+- Rerun `rs hooks` to restore generated files and executable permissions.
+- Check that `RSTACK_HOOKS` is not set to `0` in 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](#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](https://gitforwindows.org/). Use LF line endings and `/` path separators in hooks.
+
+[Yarn PnP](https://yarnpkg.com/features/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.
diff --git a/website/docs/en/guide/cli/setup.mdx b/website/docs/en/guide/cli/setup.mdx
deleted file mode 100644
index 6a96043..0000000
--- a/website/docs/en/guide/cli/setup.mdx
+++ /dev/null
@@ -1,231 +0,0 @@
-# setup
-
-import { PackageManagerTabs } from '@rspress/core/theme';
-
-The `rs setup` command installs repository-level [Git hooks](https://git-scm.com/docs/githooks) and runs them in the project that invokes the command.
-
-## Usage
-
-```bash
-rs setup [options]
-```
-
-By default, hook scripts are stored in `.rstack/hooks`, relative to the Git repository root. If the current directory is not inside a Git repository, the command skips installation.
-
-Add `rs setup` to the `prepare` script of the project that should manage the repository hooks:
-
-```json title="package.json"
-{
- "scripts": {
- "prepare": "rs setup"
- }
-}
-```
-
-Run the script once to generate the hook files:
-
-
-
-For example, create a `pre-commit` hook that runs [`rs staged`](./staged):
-
-```sh title=".rstack/hooks/pre-commit"
-rs staged
-```
-
-:::warning Existing Git hook managers
-
-`rs setup` updates the repository's [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath). It skips installation when another hooks path or existing Git hook is detected. Run `rs setup --force` to install Rstack hooks anyway.
-
-:::
-
-## Options
-
-### `--force`
-
-`--force` (or `-f`) installs Rstack hooks even when an existing Git hooks setup is detected:
-
-```bash
-rs setup --force
-```
-
-Rstack preserves the existing hook files and sets `core.hooksPath` to its generated hooks directory. While this setting is active, Git no longer runs hooks from the previous location.
-
-:::tip
-Run `rs setup --force` only once. Use `rs setup` without `--force` in the `prepare` script.
-:::
-
-### `--hooks-dir`
-
-Sets the directory for hook scripts, relative to the Git repository root.
-
-```bash
-rs setup --hooks-dir config/git-hooks
-
-# Quote paths that contain spaces
-rs setup --hooks-dir "config/git hooks"
-```
-
-When using a custom directory, add the full command to the `prepare` script of the project that manages hooks:
-
-```json title="package.json"
-{
- "scripts": {
- "prepare": "rs setup --hooks-dir config/git-hooks"
- }
-}
-```
-
-> To prevent Git hook files from being created or overwritten outside the repository through parent directory paths, the path must not contain `..`.
-
-### `--help`
-
-`--help` (or `-h`) displays the command's usage and options.
-
-```bash
-rs setup --help
-```
-
-## Hook files
-
-The default directory structure is:
-
-```text
-.rstack/
-└── hooks/
- ├── pre-commit # Repository hook script: edit and commit
- └── _/ # Generated by rs setup; ignored by Git
- ├── .gitignore
- ├── .owner
- ├── runner
- ├── pre-commit
- ├── commit-msg
- └── ...
-```
-
-Files next to `_` are repository hook scripts. The `_` directory contains generated files and is ignored by Git. `rs setup` points `core.hooksPath` to `.rstack/hooks/_`; rerun it after cloning the repository or when generated files are missing.
-
-## Supported hooks
-
-Rstack CLI supports these client-side Git hooks:
-
-- `pre-commit`
-- `pre-merge-commit`
-- `prepare-commit-msg`
-- `commit-msg`
-- `post-commit`
-- `applypatch-msg`
-- `pre-applypatch`
-- `post-applypatch`
-- `pre-rebase`
-- `post-rewrite`
-- `post-checkout`
-- `post-merge`
-- `pre-push`
-- `pre-auto-gc`
-
-Create a file with the matching name next to the `_` directory.
-
-## Hook runtime
-
-Rstack CLI runs hook scripts with POSIX `sh -e`, forwards Git's arguments and standard input, and returns the hook's exit code. Before running a hook, it 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:
-
-```bash
-RSTACK_HOOKS=0 git commit -m "Skip hooks"
-```
-
-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:
-
-```bash
-RSTACK_HOOKS=2 git commit -m "Trace hooks"
-```
-
-### Configure the hook environment
-
-Before running a hook script, Rstack CLI loads this optional POSIX shell file:
-
-```text
-${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh
-```
-
-Use it to initialize a Node.js version manager, update `PATH`, or set `RSTACK_HOOKS=0` for the current user.
-
-## Monorepo
-
-In a monorepo, the project that provides Rstack CLI may be located in a subdirectory such as `frontend/`. Running `rs setup` from that directory still installs hooks at the Git repository root:
-
-```text
-repo/.rstack/hooks/
-repo/.rstack/hooks/_/
-core.hooksPath=.rstack/hooks/_
-```
-
-Rstack CLI records `frontend` as the project that owns the hooks. Hook scripts remain at the repository root, but run from `frontend`, so they can use its configuration and dependencies without an explicit `cd`:
-
-```sh title=".rstack/hooks/pre-commit"
-rs staged
-```
-
-A Git repository has one hooks owner. Only that project should include `rs setup` in its `prepare` script. Calls from another project are skipped with a warning.
-
-To change the owner, remove `rs setup` from the previous project's `prepare` script, delete the generated `_` directory, and then run `rs setup` from the new project.
-
-## Remove hooks
-
-To remove hooks managed by Rstack CLI:
-
-1. Remove `rs setup` from the `prepare` script.
-2. Check which Git configuration scope defines the active hooks path:
-
- ```bash
- git config --show-scope --get core.hooksPath
- ```
-
-3. Unset the hooks path in the reported scope. For `local`, run:
-
- ```bash
- git config --local --unset core.hooksPath
- ```
-
- For `worktree`, run:
-
- ```bash
- git config --worktree --unset core.hooksPath
- ```
-
- If `--force` previously preserved hooks under `.git/hooks`, unsetting the path reactivates those files. Delete any obsolete files first if you do not want them to run.
-
-4. Delete `.rstack/hooks/`, or the directory passed to `--hooks-dir`.
-
-## Troubleshooting
-
-### Hook does not run
-
-- Check that the hook script has a [supported name](#supported-hooks) and is next to the `_` directory.
-- Run `git config --show-scope --get core.hooksPath` and verify the effective scope and path.
-- Rerun `rs setup` to restore generated files and executable permissions.
-- Check that `RSTACK_HOOKS` is not set to `0` in the environment or initialization file.
-- If another hooks setup is reported, run `rs setup --force`.
-- If another project is reported as the hooks owner, follow the ownership transfer steps in [Monorepo](#monorepo).
-
-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](https://gitforwindows.org/). Use LF line endings and `/` path separators in hooks.
-
-[Yarn PnP](https://yarnpkg.com/features/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.
diff --git a/website/docs/en/guide/cli/staged.mdx b/website/docs/en/guide/cli/staged.mdx
index d3938e6..941a26b 100644
--- a/website/docs/en/guide/cli/staged.mdx
+++ b/website/docs/en/guide/cli/staged.mdx
@@ -1,10 +1,14 @@
+---
+description: 'Run lint-staged tasks against Git-staged files with the rs staged command.'
+---
+
# staged
The `rs staged` command uses [lint-staged](https://github.com/lint-staged/lint-staged) to run tasks against files staged in Git.
`rs staged` can run linters, formatters, or other checks on staged files before committing code.
-A common pattern is to pair `rs staged` with [`rs setup`](./setup) and run staged-file tasks from a `pre-commit` hook.
+A common pattern is to pair `rs staged` with [`rs hooks`](./hooks) and run staged-file tasks from a `pre-commit` hook.
## Usage
diff --git a/website/docs/en/guide/git-hooks.mdx b/website/docs/en/guide/git-hooks.mdx
index 800f901..e59c6ff 100644
--- a/website/docs/en/guide/git-hooks.mdx
+++ b/website/docs/en/guide/git-hooks.mdx
@@ -6,18 +6,18 @@ description: 'Set up repository Git hooks with Rstack CLI and automatically lint
import { PackageManagerTabs } from '@rspress/core/theme';
-Use [`rs setup`](./cli/setup) to manage repository-level Git hooks that run project commands. By default, hook scripts live in `.rstack/hooks`. You can use them to validate commit messages, check code before pushing, or format files before committing.
+Use [`rs hooks`](./cli/hooks) to manage repository-level Git hooks that run project commands. By default, hook scripts live in `.rstack/hooks`. You can use them to validate commit messages, check code before pushing, or format files before committing.
-This page uses `pre-commit` as an example: first install Git hooks with `rs setup`, then run [`rs staged`](./cli/staged) from the `pre-commit` hook to lint and format the files staged for the commit.
+This page uses `pre-commit` as an example: first install Git hooks with `rs hooks`, then run [`rs staged`](./cli/staged) from the `pre-commit` hook to lint and format the files staged for the commit.
## Set up hooks
-Add `rs setup` to the `prepare` script of the project that owns the repository hooks:
+Add `rs hooks` to the `prepare` script of the project that owns the repository hooks:
```json title="package.json"
{
"scripts": {
- "prepare": "rs setup"
+ "prepare": "rs hooks"
}
}
```
@@ -33,7 +33,7 @@ Run the script once to install the hooks:
}}
/>
-`rs setup` sets the repository's `core.hooksPath` to `.rstack/hooks/_`. Verify the installation with:
+`rs hooks` sets the repository's `core.hooksPath` to `.rstack/hooks/_`. Verify the installation with:
```bash
git config --get core.hooksPath
@@ -43,7 +43,7 @@ git config --get core.hooksPath
:::tip
- The `_` directory is generated dynamically and ignored by Git by default.
-- If `rs setup` detects another hooks path or existing Git hooks, it skips installation. Run `rs setup --force` to install Rstack hooks anyway. See the [`rs setup` guide](./cli/setup) for details.
+- If `rs hooks` detects another hooks path or existing Git hooks, it skips installation. Run `rs hooks --force` to install Rstack hooks anyway. See the [`rs hooks` guide](./cli/hooks) for details.
:::
@@ -74,7 +74,7 @@ rs staged
### How it works
-When you run `git commit`, Git invokes the hook installed by `rs setup`. The hook executes `.rstack/hooks/pre-commit`, and `rs staged` then runs the configured tasks on the staged files.
+When you run `git commit`, Git invokes the hook installed by `rs hooks`. The hook executes `.rstack/hooks/pre-commit`, and `rs staged` then runs the configured tasks on the staged files.
`rs staged` passes matching staged files to each command. Commands in an array run in order: [`rs lint --fix`](./cli/lint) first applies available fixes, then [`rs fmt`](./cli/fmt) formats the result. Remove `--fix` if lint errors should block the commit without changing files.
diff --git a/website/docs/en/guide/quick-start.mdx b/website/docs/en/guide/quick-start.mdx
index ec64840..452237d 100644
--- a/website/docs/en/guide/quick-start.mdx
+++ b/website/docs/en/guide/quick-start.mdx
@@ -148,7 +148,7 @@ The following commands are available:
- [`rs check`](./cli/check): Run linting and formatting checks, with optional TypeScript type checking.
- [`rs lint`](./cli/lint): Lint source code with Rslint.
- [`rs fmt`](./cli/fmt): Format code.
-- [`rs setup`](./cli/setup): Install repository-level Git hooks.
+- [`rs hooks`](./cli/hooks): Install, update, or uninstall repository-level Git hooks.
- [`rs staged`](./cli/staged): Run tasks against files staged in Git with lint-staged.
## Configure Rstack CLI \{#configure-rstack}
diff --git a/website/docs/zh/guide/cli/_meta.json b/website/docs/zh/guide/cli/_meta.json
index 5357606..c228ad7 100644
--- a/website/docs/zh/guide/cli/_meta.json
+++ b/website/docs/zh/guide/cli/_meta.json
@@ -8,6 +8,6 @@
"check",
"lint",
"fmt",
- "setup",
+ "hooks",
"staged"
]
diff --git a/website/docs/zh/guide/cli/hooks.mdx b/website/docs/zh/guide/cli/hooks.mdx
new file mode 100644
index 0000000..9131cc5
--- /dev/null
+++ b/website/docs/zh/guide/cli/hooks.mdx
@@ -0,0 +1,247 @@
+---
+description: '使用 Rstack CLI 安装、配置、排查并安全移除仓库级 Git hooks。'
+---
+
+# hooks
+
+import { PackageManagerTabs } from '@rspress/core/theme';
+
+`rs hooks` 命令用于安装、更新和卸载仓库级 [Git hooks](https://git-scm.com/docs/githooks)。hook 脚本会在执行安装命令的项目目录中运行。
+
+## 用法 \{#usage}
+
+```bash
+rs hooks [options]
+rs hooks uninstall
+```
+
+直接运行 `rs hooks` 即可安装或更新 hooks。
+
+:::tip 别名
+`rs setup` 是 `rs hooks` 的别名。
+:::
+
+## 安装 hooks \{#install-hooks}
+
+hook 脚本默认存放在 Git 仓库根目录的 `.rstack/hooks` 中。如果当前目录不在 Git 仓库内,命令会跳过安装。
+
+在负责管理仓库 hooks 的项目中,将 `rs hooks` 添加到 `package.json` 的 `prepare` 脚本:
+
+```json title="package.json"
+{
+ "scripts": {
+ "prepare": "rs hooks"
+ }
+}
+```
+
+执行一次该脚本,完成 hooks 安装:
+
+
+
+例如,创建一个 `pre-commit` hook,并在其中运行 [`rs staged`](./staged):
+
+```sh title=".rstack/hooks/pre-commit"
+rs staged
+```
+
+安装命令可以安全地重复执行,并且不会加载 `rstack.config.*`。克隆仓库后或生成的 hook 文件缺失时,请再次运行 `rs hooks`。
+
+:::warning 已有 Git hook 管理工具
+
+`rs hooks` 会更新仓库的 [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath)。如果检测到其他 hooks 路径或已有 Git hooks,命令会跳过安装。可运行 `rs hooks --force`,改用 Rstack 管理 hooks。
+
+:::
+
+## 安装选项 \{#install-options}
+
+### `--force`
+
+即使已经存在其他 Git hooks 配置,也可以使用 `--force`(或 `-f`)安装 Rstack hooks:
+
+```bash
+rs hooks --force
+```
+
+Rstack 会保留原有 hook 文件,并将 `core.hooksPath` 指向其生成的 hooks 目录。该配置生效期间,Git 不会执行原路径下的 hooks。
+
+`--force` 无法替换由其他 Rstack 项目管理的 hooks。
+
+:::tip
+`rs hooks --force` 只需运行一次。`prepare` 脚本中应使用不带 `--force` 的 `rs hooks`。
+:::
+
+### `--hooks-dir`
+
+指定 hook 脚本的自定义存放目录,路径相对于 Git 仓库根目录。
+
+```bash
+rs hooks --hooks-dir config/git-hooks
+
+# 路径包含空格时需要使用引号
+rs hooks --hooks-dir "config/git hooks"
+```
+
+使用自定义目录时,请将完整命令写入负责管理 hooks 的项目 `package.json`:
+
+```json title="package.json"
+{
+ "scripts": {
+ "prepare": "rs hooks --hooks-dir config/git-hooks"
+ }
+}
+```
+
+> 路径中不能包含 `..`,以免通过父目录路径在仓库之外创建或覆盖 hook 文件。
+
+### `--help`
+
+`--help`(或 `-h`)用于显示命令的用法、子命令和安装选项。
+
+```bash
+rs hooks --help
+```
+
+## 卸载 hooks \{#uninstall-hooks}
+
+请在安装 hooks 的项目目录中运行:
+
+```bash
+rs hooks uninstall
+```
+
+Rstack 会自动定位当前生效的 hooks,并移除 `core.hooksPath` 配置和生成的 `_` 目录,但不会删除 `.rstack/hooks/pre-commit` 等项目 hook 文件。由其他项目或工具管理的 hooks 不会被删除。
+
+如果不希望再次安装 hooks,请从 `prepare` 脚本中移除 `rs hooks`。
+
+如果之前使用 `--force` 接管了 `.git/hooks` 中的 hooks,卸载后这些 hooks 会重新生效。
+
+## Hook 文件 \{#hook-files}
+
+默认目录结构如下:
+
+```text
+.rstack/
+└── hooks/
+ ├── pre-commit # 仓库 hook 脚本:编辑并提交
+ └── _/ # 由 rs hooks 生成;默认被 Git 忽略
+ ├── .gitignore
+ ├── .owner
+ ├── runner
+ ├── pre-commit
+ ├── commit-msg
+ └── ...
+```
+
+与 `_` 同级的文件是仓库 hook 脚本。`_` 目录包含生成文件,并由 Git 忽略。`rs hooks` 会将 `core.hooksPath` 指向 `.rstack/hooks/_`。
+
+## 支持的 hooks \{#supported-hooks}
+
+Rstack CLI 支持以下客户端 Git hooks:
+
+- `pre-commit`
+- `pre-merge-commit`
+- `prepare-commit-msg`
+- `commit-msg`
+- `post-commit`
+- `applypatch-msg`
+- `pre-applypatch`
+- `post-applypatch`
+- `pre-rebase`
+- `post-rewrite`
+- `post-checkout`
+- `post-merge`
+- `pre-push`
+- `pre-auto-gc`
+
+在与 `_` 同级的位置创建对应的同名文件即可。
+
+## Hook 运行时 \{#hook-runtime}
+
+Rstack CLI 使用 POSIX `sh -e` 运行 hook 脚本。它会转发 Git 提供的参数和标准输入,并返回 hook 的退出码。运行 hook 前,Rstack 会切换到安装 hooks 的项目,并将该项目的 `node_modules/.bin` 添加到 `PATH` 开头。
+
+### 禁用与调试 \{#disable-and-debug}
+
+将 `RSTACK_HOOKS` 设为 `0`,可以跳过安装或 hook 执行:
+
+```bash
+RSTACK_HOOKS=0 git commit -m "Skip hooks"
+```
+
+将 `RSTACK_HOOKS` 设为 `2`,可以跟踪 Rstack CLI 的 hook 运行时,包括调用 hook 脚本和处理退出码等步骤;如需跟踪 hook 脚本内部的命令,请在脚本中添加 `set -x`:
+
+```bash
+RSTACK_HOOKS=2 git commit -m "Trace hooks"
+```
+
+### 配置 hook 运行环境 \{#configure-the-hook-environment}
+
+运行 hook 脚本前,Rstack CLI 会加载以下可选的 POSIX shell 文件:
+
+```text
+${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh
+```
+
+可以在其中初始化 Node.js 版本管理器、更新 `PATH`,或为当前用户设置 `RSTACK_HOOKS=0`。
+
+## 所有权保护 \{#ownership-safety}
+
+每个生成的 hooks 目录都会记录所属项目。只有该项目应在 `prepare` 脚本中调用 `rs hooks`。其他项目即使使用 `--force` 调用安装命令,也会被跳过;卸载命令同样会拒绝删除其他项目的 hooks。
+
+如需转移所有权:
+
+1. 从原项目的 `prepare` 脚本中移除 `rs hooks`。
+2. 在原项目中运行 `rs hooks uninstall`。
+3. 将 `rs hooks` 添加到新项目的 `prepare` 脚本,并运行一次。
+
+## Monorepo \{#monorepo}
+
+在 monorepo 中,提供 Rstack CLI 的项目可能位于 `frontend/` 等子目录。在该目录中运行 `rs hooks`,hooks 仍会安装到 Git 仓库根目录:
+
+```text
+repo/.rstack/hooks/
+repo/.rstack/hooks/_/
+core.hooksPath=.rstack/hooks/_
+```
+
+Rstack 会将 `frontend` 记录为 hooks 所属项目。hook 脚本仍保存在仓库根目录,但会从 `frontend` 目录运行,因此可以直接使用其中的配置和依赖,无需显式执行 `cd`:
+
+```sh title=".rstack/hooks/pre-commit"
+rs staged
+```
+
+## Worktree 行为 \{#worktree-behavior}
+
+Rstack 会保留当前生效的 `core.hooksPath` 所在的 Git 配置作用域。如果 linked worktree 使用的是 worktree 作用域配置,`rs hooks --force` 会在同一作用域中替换它,而不会写入一个被 Git 忽略的 local 配置。
+
+`rs hooks uninstall` 也会从同一作用域中移除配置。卸载 worktree 作用域的安装只影响当前 worktree,不会改变其他 worktree 中的 hooks。local 作用域的 `core.hooksPath` 会在多个 worktree 之间共享,因此更改或移除该配置会影响所有未覆盖它的 worktree。
+
+## 故障排查 \{#troubleshooting}
+
+### Hook 未运行 \{#hook-does-not-run}
+
+- 确认 hook 脚本使用[支持的名称](#supported-hooks),并与 `_` 目录同级。
+- 运行 `git config --show-scope --get core.hooksPath`,检查当前生效的配置作用域和路径。
+- 重新运行 `rs hooks`,恢复生成文件及其可执行权限。
+- 检查环境变量或初始化文件中是否设置了 `RSTACK_HOOKS=0`。
+- 如果命令检测到其他 hooks 配置,请运行 `rs hooks --force`。
+- 如果命令提示其他项目是 hooks owner,请按照[所有权保护](#ownership-safety)中的步骤转移 owner。
+
+hook 脚本不需要可执行权限,因为 Rstack CLI 会使用 `sh` 运行它。
+
+### 找不到命令 \{#command-not-found}
+
+退出码为 127 时,Rstack CLI 会打印实际生效的 `PATH`。如果 GUI Git 客户端找不到 Node.js 或包管理器,请在 `hooks-init.sh` 中初始化相关环境。
+
+### Windows 与 Yarn \{#windows-and-yarn}
+
+在 Windows 上,hooks 会通过 [Git for Windows](https://gitforwindows.org/) 自带的 POSIX shell 运行。请在 hook 中使用 LF 换行符和 `/` 路径分隔符。
+
+[Yarn PnP](https://yarnpkg.com/features/pnp) 不提供 `node_modules/.bin`。请通过 Yarn 脚本运行工具,例如 `yarn run test`;必要时可通过 `hooks-init.sh` 配置 Node.js 和 Yarn。
diff --git a/website/docs/zh/guide/cli/setup.mdx b/website/docs/zh/guide/cli/setup.mdx
deleted file mode 100644
index cdef8ab..0000000
--- a/website/docs/zh/guide/cli/setup.mdx
+++ /dev/null
@@ -1,231 +0,0 @@
-# setup
-
-import { PackageManagerTabs } from '@rspress/core/theme';
-
-`rs setup` 命令用于安装仓库级 [Git hooks](https://git-scm.com/docs/githooks),并在调用该命令的项目中运行 hooks。
-
-## 用法 \{#usage}
-
-```bash
-rs setup [options]
-```
-
-hook 脚本默认存放在 Git 仓库根目录下的 `.rstack/hooks`。如果当前目录不属于 Git 仓库,命令会跳过安装。
-
-在负责管理仓库 hooks 的项目 `package.json` 中添加 `prepare` 脚本:
-
-```json title="package.json"
-{
- "scripts": {
- "prepare": "rs setup"
- }
-}
-```
-
-执行一次该脚本,生成 hook 文件:
-
-
-
-例如,创建一个 `pre-commit` hook,并在其中运行 [`rs staged`](./staged):
-
-```sh title=".rstack/hooks/pre-commit"
-rs staged
-```
-
-:::warning 已有 Git hook 管理工具
-
-`rs setup` 会更新仓库的 [`core.hooksPath`](https://git-scm.com/docs/git-config#Documentation/git-config.txt-corehooksPath)。检测到其他 hooks 路径或已有 Git hook 时,命令会跳过安装。可运行 `rs setup --force` 强制安装 Rstack hooks。
-
-:::
-
-## 选项 \{#options}
-
-### `--force`
-
-检测到已有 Git hooks 配置时,可使用 `--force`(或 `-f`)强制安装 Rstack hooks:
-
-```bash
-rs setup --force
-```
-
-Rstack 会保留原有 hook 文件,并将 `core.hooksPath` 指向 Rstack 生成的 hooks 目录。该配置生效期间,Git 不再执行原路径下的 hooks。
-
-:::tip
-`rs setup --force` 只需运行一次。`prepare` 脚本中应使用不带 `--force` 的 `rs setup`。
-:::
-
-### `--hooks-dir`
-
-设置 hook 脚本的存放目录,路径相对于 Git 仓库根目录。
-
-```bash
-rs setup --hooks-dir config/git-hooks
-
-# 路径包含空格时需要使用引号
-rs setup --hooks-dir "config/git hooks"
-```
-
-使用自定义目录时,请将完整命令写入负责管理 hooks 的项目 `package.json`:
-
-```json title="package.json"
-{
- "scripts": {
- "prepare": "rs setup --hooks-dir config/git-hooks"
- }
-}
-```
-
-> 为避免通过父目录路径在仓库之外创建或覆盖 Git hook 文件,路径中不能包含 `..`。
-
-### `--help`
-
-`--help`(或 `-h`)用于显示命令的用法和选项。
-
-```bash
-rs setup --help
-```
-
-## Hook 文件 \{#hook-files}
-
-默认目录结构如下:
-
-```text
-.rstack/
-└── hooks/
- ├── pre-commit # 仓库 hook 脚本:编辑并提交
- └── _/ # 由 rs setup 生成;默认被 Git 忽略
- ├── .gitignore
- ├── .owner
- ├── runner
- ├── pre-commit
- ├── commit-msg
- └── ...
-```
-
-与 `_` 同级的文件是仓库 hook 脚本。`_` 目录包含生成文件,并由 Git 忽略。`rs setup` 会将 `core.hooksPath` 指向 `.rstack/hooks/_`;克隆仓库后或生成文件缺失时,请重新运行该命令。
-
-## 支持的 hooks \{#supported-hooks}
-
-Rstack CLI 支持以下客户端 Git hooks:
-
-- `pre-commit`
-- `pre-merge-commit`
-- `prepare-commit-msg`
-- `commit-msg`
-- `post-commit`
-- `applypatch-msg`
-- `pre-applypatch`
-- `post-applypatch`
-- `pre-rebase`
-- `post-rewrite`
-- `post-checkout`
-- `post-merge`
-- `pre-push`
-- `pre-auto-gc`
-
-在与 `_` 同级的位置创建对应的同名文件即可。
-
-## Hook 运行时 \{#hook-runtime}
-
-Rstack CLI 使用 POSIX `sh -e` 运行 hook 脚本,并转发 Git 提供的参数和标准输入,同时返回 hook 的退出码。运行 hook 前,Rstack CLI 会切换到安装 hooks 的项目,并将该项目的 `node_modules/.bin` 添加到 `PATH` 开头。
-
-### 禁用与调试 \{#disable-and-debug}
-
-将 `RSTACK_HOOKS` 设为 `0`,可以跳过安装或 hook 执行:
-
-```bash
-RSTACK_HOOKS=0 git commit -m "Skip hooks"
-```
-
-将 `RSTACK_HOOKS` 设为 `2`,可以跟踪 Rstack CLI 的 hook 运行时,包括调用 hook 脚本和处理退出码等步骤;如需跟踪 hook 脚本内部的命令,请在脚本中添加 `set -x`:
-
-```bash
-RSTACK_HOOKS=2 git commit -m "Trace hooks"
-```
-
-### 配置 hook 运行环境 \{#configure-the-hook-environment}
-
-运行 hook 脚本前,Rstack CLI 会加载以下可选的 POSIX shell 文件:
-
-```text
-${XDG_CONFIG_HOME:-$HOME/.config}/rstack/hooks-init.sh
-```
-
-可以在其中初始化 Node.js 版本管理器、更新 `PATH`,或为当前用户设置 `RSTACK_HOOKS=0`。
-
-## Monorepo \{#monorepo}
-
-在 monorepo 中,提供 Rstack CLI 的项目可能位于 `frontend/` 等子目录。从该目录运行 `rs setup` 时,hooks 仍会安装到 Git 仓库根目录:
-
-```text
-repo/.rstack/hooks/
-repo/.rstack/hooks/_/
-core.hooksPath=.rstack/hooks/_
-```
-
-Rstack CLI 会将 `frontend` 记录为负责管理 hooks 的项目。hook 脚本仍位于仓库根目录,但会从 `frontend` 目录运行,因此可以直接使用其中的配置和依赖,无需显式执行 `cd`:
-
-```sh title=".rstack/hooks/pre-commit"
-rs staged
-```
-
-一个 Git 仓库只能有一个 hooks owner。只有负责管理 hooks 的项目应在 `prepare` 脚本中调用 `rs setup`。其他项目调用时会收到警告并跳过。
-
-如需更换 owner,请先从原项目的 `prepare` 脚本中移除 `rs setup`,删除生成的 `_` 目录,再从新项目运行 `rs setup`。
-
-## 移除 hooks \{#remove-hooks}
-
-如需移除由 Rstack CLI 管理的 hooks:
-
-1. 从 `prepare` 脚本中移除 `rs setup`。
-2. 检查当前生效的 hooks 路径来自哪个 Git 配置作用域:
-
- ```bash
- git config --show-scope --get core.hooksPath
- ```
-
-3. 根据输出,在对应作用域中取消 hooks 路径配置。作用域为 `local` 时运行:
-
- ```bash
- git config --local --unset core.hooksPath
- ```
-
- 作用域为 `worktree` 时运行:
-
- ```bash
- git config --worktree --unset core.hooksPath
- ```
-
- 如果之前通过 `--force` 保留了 `.git/hooks` 下的 hooks,取消路径配置会重新启用这些文件。如果不希望它们运行,请先删除不再需要的文件。
-
-4. 删除 `.rstack/hooks/` 或通过 `--hooks-dir` 指定的目录。
-
-## 故障排查 \{#troubleshooting}
-
-### Hook 未运行 \{#hook-does-not-run}
-
-- 确认 hook 脚本使用[支持的名称](#supported-hooks),并与 `_` 目录同级。
-- 运行 `git config --show-scope --get core.hooksPath`,检查当前生效的配置作用域和路径。
-- 重新运行 `rs setup`,恢复生成文件及其可执行权限。
-- 检查环境变量或初始化文件中是否设置了 `RSTACK_HOOKS=0`。
-- 如果命令提示存在其他 hooks 配置,请运行 `rs setup --force`。
-- 如果命令提示其他项目是 hooks owner,请按照 [Monorepo](#monorepo) 中的步骤转移 owner。
-
-hook 脚本不需要可执行权限,因为 Rstack CLI 会使用 `sh` 运行它。
-
-### 找不到命令 \{#command-not-found}
-
-退出码为 127 时,Rstack CLI 会打印实际生效的 `PATH`。如果 GUI Git 客户端找不到 Node.js 或包管理器,请在 `hooks-init.sh` 中初始化相关环境。
-
-### Windows 与 Yarn \{#windows-and-yarn}
-
-在 Windows 上,hooks 会通过 [Git for Windows](https://gitforwindows.org/) 自带的 POSIX shell 运行。请在 hook 中使用 LF 换行符和 `/` 路径分隔符。
-
-[Yarn PnP](https://yarnpkg.com/features/pnp) 不提供 `node_modules/.bin`。请通过 Yarn 脚本运行工具,例如 `yarn run test`;必要时可通过 `hooks-init.sh` 配置 Node.js 和 Yarn。
diff --git a/website/docs/zh/guide/cli/staged.mdx b/website/docs/zh/guide/cli/staged.mdx
index 4821c3c..897c7f7 100644
--- a/website/docs/zh/guide/cli/staged.mdx
+++ b/website/docs/zh/guide/cli/staged.mdx
@@ -1,10 +1,14 @@
+---
+description: '使用 rs staged 命令对 Git 暂存文件运行 lint-staged 任务。'
+---
+
# staged
`rs staged` 命令使用 [lint-staged](https://github.com/lint-staged/lint-staged) 对 Git 暂存文件运行任务。
`rs staged` 可用于在提交代码前,对暂存文件运行 linter、格式化工具或其他检查。
-常见做法是将 `rs staged` 与 [`rs setup`](./setup) 配合使用,通过 `pre-commit` hook 运行暂存文件任务。
+常见做法是将 `rs staged` 与 [`rs hooks`](./hooks) 配合使用,通过 `pre-commit` hook 运行暂存文件任务。
## 用法 \{#usage}
diff --git a/website/docs/zh/guide/git-hooks.mdx b/website/docs/zh/guide/git-hooks.mdx
index 3a04d20..bdb3be7 100644
--- a/website/docs/zh/guide/git-hooks.mdx
+++ b/website/docs/zh/guide/git-hooks.mdx
@@ -6,18 +6,18 @@ description: '使用 Rstack CLI 配置仓库级 Git hooks,并在提交前自
import { PackageManagerTabs } from '@rspress/core/theme';
-使用 [`rs setup`](./cli/setup) 可以统一管理仓库级 Git hooks,并通过 hook 脚本运行项目命令。hook 脚本默认存放在 `.rstack/hooks` 中,可用于校验提交信息、推送前检查代码、提交前格式化文件等场景。
+使用 [`rs hooks`](./cli/hooks) 可以统一管理仓库级 Git hooks,并通过 hook 脚本运行项目命令。hook 脚本默认存放在 `.rstack/hooks` 中,可用于校验提交信息、推送前检查代码、提交前格式化文件等场景。
-下面以 `pre-commit` 为例:先通过 `rs setup` 安装 Git hooks,再在 `pre-commit` hook 中运行 [`rs staged`](./cli/staged),对本次提交的暂存文件进行代码检查和格式化。
+下面以 `pre-commit` 为例:先通过 `rs hooks` 安装 Git hooks,再在 `pre-commit` hook 中运行 [`rs staged`](./cli/staged),对本次提交的暂存文件进行代码检查和格式化。
## 安装 hooks \{#set-up-hooks}
-在负责管理仓库 hooks 的项目中,将 `rs setup` 添加到 `package.json` 的 `prepare` 脚本:
+在负责管理仓库 hooks 的项目中,将 `rs hooks` 添加到 `package.json` 的 `prepare` 脚本:
```json title="package.json"
{
"scripts": {
- "prepare": "rs setup"
+ "prepare": "rs hooks"
}
}
```
@@ -33,7 +33,7 @@ import { PackageManagerTabs } from '@rspress/core/theme';
}}
/>
-`rs setup` 会将仓库的 `core.hooksPath` 设为 `.rstack/hooks/_`,可以通过以下命令确认是否安装成功:
+`rs hooks` 会将仓库的 `core.hooksPath` 设为 `.rstack/hooks/_`,可以通过以下命令确认是否安装成功:
```bash
git config --get core.hooksPath
@@ -43,7 +43,7 @@ git config --get core.hooksPath
:::tip
- `_` 目录由命令动态生成,且默认被 Git 忽略。
-- 如果检测到其他 hooks 路径或已有 Git hooks,`rs setup` 会跳过安装。可运行 `rs setup --force` 强制安装 Rstack hooks。详细说明请参考 [`rs setup` 指南](./cli/setup)。
+- 如果检测到其他 hooks 路径或已有 Git hooks,`rs hooks` 会跳过安装。可运行 `rs hooks --force` 强制安装 Rstack hooks。详细说明请参考 [`rs hooks` 指南](./cli/hooks)。
:::
@@ -74,7 +74,7 @@ rs staged
### 执行流程 \{#how-it-works}
-运行 `git commit` 时,Git 会调用 `rs setup` 安装的 hook。该 hook 会执行 `.rstack/hooks/pre-commit`,再由 `rs staged` 对暂存文件运行配置的任务。
+运行 `git commit` 时,Git 会调用 `rs hooks` 安装的 hook。该 hook 会执行 `.rstack/hooks/pre-commit`,再由 `rs staged` 对暂存文件运行配置的任务。
`rs staged` 会将匹配的暂存文件传给对应命令,数组中的命令按顺序执行,[`rs lint --fix`](./cli/lint) 先修复可自动处理的问题,再由 [`rs fmt`](./cli/fmt) 统一格式。如果只希望代码检查阻止提交而不修改文件,可以移除 `--fix`。
diff --git a/website/docs/zh/guide/quick-start.mdx b/website/docs/zh/guide/quick-start.mdx
index 4cc43cc..074a84f 100644
--- a/website/docs/zh/guide/quick-start.mdx
+++ b/website/docs/zh/guide/quick-start.mdx
@@ -148,7 +148,7 @@ Rstack CLI 提供以下命令:
- [`rs check`](./cli/check):运行 lint 和格式检查,并可选启用 TypeScript 类型检查。
- [`rs lint`](./cli/lint):使用 Rslint 检查源代码。
- [`rs fmt`](./cli/fmt):格式化代码。
-- [`rs setup`](./cli/setup):安装仓库级 Git hooks。
+- [`rs hooks`](./cli/hooks):安装、更新或卸载仓库级 Git hooks。
- [`rs staged`](./cli/staged):使用 lint-staged 对 Git 暂存区中的文件运行任务。
## 配置 Rstack CLI \{#configure-rstack}