Changing ships from husky and lint-staged
husky runs the scripts in .husky/ as Git hooks. lint-staged picks the staged cargo that matches each glob and runs yer commands on it, usually from a husky pre-commit script. hk does both jobs: its hooks select files, run steps, and can load fixes aboard and keep unstaged work safe.
hk has no converter for these hook managers. (hk migrate pre-commit handles only the pre-commit framework.) Ye translate by hand, matey, and the map is direct: a lint-staged glob becomes a step's glob, its commands become fix or check, and a husky script becomes a hook.
Differences to check first
- Local binaries. husky adds
node_modules/.bintoPATHfor its scripts, and lint-staged finds locally installed tools. hk runs commands with thePATHit was started with. Call project tools withnpxor yer package manager's exec command, setprefix = "npx"on a step, or put the tools onPATH. The mise integration guide shows a Node.js setup. - Concurrency. lint-staged runs the commands for one glob in sequence and runs the globs concurrently. hk has all hands haul at once, and lashes steps that select the same files with read and write locks. Put commands that must run in order in one step joined with
&&, or in separate steps linked bydepends. See order steps deliberately. - Unstaged changes. lint-staged backs up yer state in a Git stash and sets aside unstaged changes in partially staged files while its tasks run, unless ye pass
--no-stash. hk stows unstaged work in the hold when a hook setsstash = "git"; with nostashsetting it leaves unstaged work in place. See stashing and partial commits. - Staging fixes. lint-staged loads what its tasks changed aboard. hk's
pre-commithook does the same for steps that fix, by default.stage = falsewithfail_on_fix = truestops the voyage for review instead, like lint-staged's--fail-on-changes. See review fixes before committing. - Paths. lint-staged passes absolute paths unless ye set
--relative. hk's{{files}}are relative to the ship, or to the step'sdir. - Failures. Both stop after the first failure by default.
hk run pre-commit --no-fail-fastreports every squall, like--continue-on-error. - Globs. Both match a pattern without a slash, such as
*.js, against files at any depth. lint-staged negation patterns such as!(*.test).jsbecome anexcludelist. - No function configs. lint-staged accepts JavaScript functions that build commands. hk steps are strings, so build the command with the
{{files}}placeholder and the other template variables.
Changing ships
- Write
hk.pklfrom yer lint-staged config and husky scripts, using the maps below.hk initcan generate a starting chart for the tools it detects. See getting started. - Run
hk validate, then preview what a hook selects withhk run pre-commit --plan. - Take husky down:
- Delete the
preparescript ("prepare": "husky") frompackage.json. husky setscore.hooksPathto.husky/_each time it runs, so a leftoverpreparebrings it back. - Uninstall
huskyandlint-stagedwith yer package manager and delete.husky/. - Run
git config --unset core.hooksPath.
- Delete the
- Run
hk install. On Git 2.54 and newer hk registers its hooks in Git config, which runs alongside hooks fromcore.hooksPath, so both husky and hk sound until ye complete step 3. On older Git, hk writes hook files to the hooks directory, and acore.hooksPaththat points elsewhere can stop them from running;hk installwarns when it findscore.hooksPathset.
Every shipmate who has a clone must run hk install, and must unset core.hooksPath if it still points at .husky/_.
Hooks and scripts
| husky | hk |
|---|---|
.husky/pre-commit, commit-msg, pre-push | A hook of the same name under hooks. See other Git events for the others hk handles. |
npx lint-staged in pre-commit | The steps of the pre-commit hook, one per lint-staged glob |
npx --no -- commitlint --edit $1 in commit-msg | check = "npx commitlint --edit {{commit_msg_file}}". See commit-message hooks. |
npm test in pre-push | A pre-push step with check = "npm test" and no glob, so it always runs |
HUSKY=0 git commit | HK=0 git commit |
A pre-push hook also receives the remote name and URL as {{hook_args}}. A step without a glob runs even when no files match.
lint-staged options
| lint-staged | hk |
|---|---|
A glob key such as "*.{js,ts}" | glob = "*.{js,ts}" on a step. A List or a Regex also works. |
| A command string | fix for a command that mends files, check for one that only inspects |
| Files appended to the command | {{files}}, written where the files belong |
| A list of commands for one glob | One step with the commands joined by &&, or one step each linked by depends |
! negation | exclude |
--no-stash | stash = "none", or leave stash unset |
| Default backup and restore | stash = "git" on the hook |
--fail-on-changes | fail_on_fix = true and stage = false on the hook |
--continue-on-error | --no-fail-fast, or fail_fast = false |
--concurrent <n> | --jobs <n> or jobs = n |
| Per-directory configs in a monorepo | subprojects. See monorepos. |
Example
A husky and lint-staged setup. In package.json:
{
"scripts": { "prepare": "husky" },
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"],
"*.css": "stylelint --fix",
"*.md": "prettier --write"
}
}In .husky/pre-commit:
npx lint-stagedIn .husky/commit-msg:
npx --no -- commitlint --edit $1In .husky/pre-push:
npm testThe same hooks in hk:
amends "package://github.com/jdx/hk/releases/download/v2.5.0/hk@2.5.0#/Config.pkl"
hooks {
["pre-commit"] {
fix = true
stash = "git"
steps {
["eslint"] {
glob = "*.{js,ts}"
fix = "npx eslint --fix {{files}}"
}
["prettier"] {
glob = "*.{js,ts,md}"
depends = "eslint"
fix = "npx prettier --write {{files}}"
}
["stylelint"] {
glob = "*.css"
fix = "npx stylelint --fix {{files}}"
}
}
}
["commit-msg"] {
steps {
["commitlint"] { check = "npx commitlint --edit {{commit_msg_file}}" }
}
}
["pre-push"] {
steps {
["test"] { check = "npm test" }
}
}
}- lint-staged ran
eslint --fixand thenprettier --writeon JavaScript and TypeScript files.depends = "eslint"keeps that order. Theprettierstep also covers Markdown, which lint-staged handled with a separate key. stylelinthas no dependency, so hk runs it alongsideeslint.hk run pre-commit --planshows which steps and files a voyage would use.
