Back to Prek

Migrating from Other Hook Tools

docs/migration.md

0.5.13.9 KB
Original Source

Migrating from Other Hook Tools

Move one hook at a time when replacing an existing setup. Keep the old hook available until the equivalent prek hook has run successfully on the whole repository and in CI.

From pre-commit

Start with the two-step path in the Quickstart. The Compatibility and Differences pages cover the cases worth checking when a repository depends on less common behavior.

From lint-staged or Husky

A lint-staged command usually becomes a repo = "local" hook. For example, this hook runs the project's ESLint installation and lets prek append matching filenames:

=== "prek.toml"

```toml
[[repos]]
repo = "local"

[[repos.hooks]]
id = "eslint"
name = "eslint"
language = "system"
entry = "npm exec -- eslint"
files = "\\.[cm]?[jt]sx?$"
pass_filenames = true
```

=== ".pre-commit-config.yaml"

```yaml
repos:
  - repo: local
    hooks:
      - id: eslint
        name: eslint
        language: system
        entry: npm exec -- eslint
        files: '\.[cm]?[jt]sx?$'
        pass_filenames: true
```

The project must install its Node dependencies before this hook runs. Map the rest of the setup as follows:

Existing conceptprek equivalent
lint-staged file globfiles, types, types_or, and exclude
Filenames appended to a commandpass_filenames = true, which is the default
Command discovers its own filespass_filenames = false
Shell pipeline or expansionPrefer a direct command; otherwise set shell explicitly
Husky hook scriptA Git stage plus prek install

If a Husky script also performs unrelated work, keep that work in a project script and call the script from a local hook. This keeps the Git shim small and makes the command easy to run outside Git.

From Lefthook

Translate each Lefthook command into a local hook:

Lefthook conceptprek equivalent
Hook name such as pre-commit or pre-pushHook stages and an installed Git shim
commands.<name>.runLocal hook entry and args
{staged_files}The default pass_filenames = true behavior
glob and excludefiles, types, and exclude
Parallel command groupsHooks with the same priority

Installing a shim and making a hook eligible for that stage are separate choices. For example:

toml
default_install_hook_types = ["pre-commit", "pre-push"]

[[repos]]
repo = "local"

[[repos.hooks]]
id = "tests"
name = "tests"
language = "system"
entry = "cargo test"
pass_filenames = false
stages = ["pre-push"]

Hooks remain sequential when priority is omitted. Give independent hooks the same explicit priority only after checking that they do not modify the same files or contend for shared state.

Keep the existing hook during rollout

If .git/hooks/<hook-name> already belongs to another tool, a normal prek install moves it to <hook-name>.legacy and installs prek in migration mode. The prek shim runs both hook implementations.

bash
prek install

When the migration is complete, replace the legacy hook:

bash
prek install --force

Before using --force, make sure the old hook contains no checks that are still needed. If you uninstall while migration mode is active, prek uninstall restores the legacy hook to its original path.

Migration checklist

  1. Put each existing check in a local or remote hook.
  2. Confirm file filtering and whether the command accepts filenames.
  3. Configure every Git stage that the old tool handled.
  4. Stage the config and run prek run --all-files.
  5. Add the same command to CI.
  6. Install the Git shims, initially preserving the old hook if useful.
  7. Remove the old tool and dependencies only after local and CI runs agree.