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}