-
Notifications
You must be signed in to change notification settings - Fork 1
Rules reference
Fisherman provides a comprehensive set of rules for validating and automating Git hooks. Rules can be combined, use variables, and execute conditionally.
All rules support these common fields:
-
type(required) - The rule type identifier -
when(optional) - Conditional expression for executing the rule ( see Variables and Templates) -
extract(optional) - Override global variable extraction for this rule
All rules execute sequentially in the order they are defined. Every rule is evaluated; all failures are collected and reported before the hook exits with a non-zero code.
Rules for validating and enforcing commit message formats. These rules are typically used with the commit-msg hook.
Validates that the commit message matches a regular expression pattern.
Parameters:
-
regex(required) - Regular expression pattern to match against the commit message
Example - Conventional Commits:
[[hooks.commit-msg]]
type = "message-regex"
regex = "^(feat|fix|docs|style|refactor|perf|test|chore)(\\(.+\\))?:\\s.+"Example - Require Issue Number:
[[hooks.commit-msg]]
type = "message-regex"
regex = "^(PROJ-\\d+|NO-ISSUE):\\s.+"Use cases:
- Enforce conventional commit format
- Require issue tracking numbers
- Prevent certain words or patterns
- Validate commit message structure
Validates that the commit message starts with a specific prefix.
Parameters:
-
prefix(required) - String that the commit message must start with
Example - Static Prefix:
[[hooks.commit-msg]]
type = "message-prefix"
prefix = "feat: "Example - Dynamic Prefix with Variables:
extract = ["branch?:^(?<IssueNumber>PROJ-\\d+)-.*$"]
[[hooks.commit-msg]]
type = "message-prefix"
when = "is_def_var(\"IssueNumber\")"
prefix = "{{IssueNumber}}: "Use cases:
- Enforce consistent commit message prefixes
- Automatically add issue numbers from branch names
- Require specific commit types
Validates that the commit message ends with a specific suffix.
Parameters:
-
suffix(required) - String that the commit message must end with
Example:
[[hooks.commit-msg]]
type = "message-suffix"
suffix = " [skip ci]"Example - Dynamic Suffix:
extract = ["branch?:^(?<Username>[^/]+)/.*$"]
[[hooks.commit-msg]]
type = "message-suffix"
when = "is_def_var(\"Username\")"
suffix = " (by {{Username}})"Use cases:
- Enforce required trailers or tags
- Add automated signatures
- Include metadata in commits
Rules for validating branch naming conventions. These rules are typically used with the pre-push or pre-commit
hooks.
Validates that the current branch name matches a regular expression pattern.
Parameters:
-
regex(required) - Regular expression pattern to match against the branch name
Example - Git Flow:
[[hooks.pre-push]]
type = "branch-name-regex"
regex = "^(feature|bugfix|hotfix|release)/[a-z0-9-]+$"Click to collapse
This content will be visible by default.Example - Require Issue Prefix:
[[hooks.pre-push]]
type = "branch-name-regex"
regex = "^(PROJ-\\d+|main|develop)-.*$"Use cases:
- Enforce branch naming conventions (Git Flow, GitHub Flow)
- Require issue tracking numbers in branch names
- Prevent certain branch name patterns
- Ensure lowercase or specific character sets
Validates that the current branch name starts with a specific prefix.
Parameters:
-
prefix(required) - String that the branch name must start with
Example:
[[hooks.pre-push]]
type = "branch-name-prefix"
prefix = "feature/"Use cases:
- Enforce branch type prefixes (feature/, bugfix/, etc.)
- Require team or project prefixes
- Implement simple branch naming policies
Validates that the current branch name ends with a specific suffix.
Parameters:
-
suffix(required) - String that the branch name must end with
Example:
[[hooks.pre-push]]
type = "branch-name-suffix"
suffix = "-dev"Use cases:
- Enforce environment suffixes
- Require specific branch markers
- Distinguish branch types by suffix
Rules for executing external commands and scripts.
Executes an external command with arguments and environment variables.
Parameters:
-
command(required) - Command to execute -
args(optional) - Array of command arguments -
env(optional) - Map of environment variables
Example - Run Tests:
[[hooks.pre-commit]]
type = "exec"
command = "cargo"
args = ["test"]Example - With Environment Variables:
[[hooks.pre-commit]]
type = "exec"
command = "npm"
args = ["run", "test"]
env = { NODE_ENV = "test", CI = "true" }Example - With Template Variables:
extract = ["branch?:^(?<Feature>[^/]+)/.*$"]
[[hooks.pre-commit]]
type = "exec"
when = "is_def_var(\"Feature\")"
command = "echo"
args = ["Running tests for {{Feature}}"]Success/Failure:
- Success: Command exits with code 0
- Failure: Command exits with non-zero code
Use cases:
- Run tests before committing
- Execute linters and formatters
- Build projects before pushing
- Run custom validation scripts
- Integrate with external tools
Executes a shell script with full shell features (pipes, redirections, variables, etc.).
Parameters:
-
script(required) - Shell script to execute -
env(optional) - Map of environment variables
Example - Simple Script:
[[hooks.pre-commit]]
type = "shell"
script = "cargo test && cargo clippy"Example - Multi-line Script:
[[hooks.pre-commit]]
type = "shell"
script = """
#!/bin/bash
set -e
echo "Running pre-commit checks..."
cargo fmt --check
cargo test
cargo clippy -- -D warnings
echo "All checks passed!"
"""Example - With Variables:
extract = ["branch?:^(?<IssueNumber>PROJ-\\d+)-.*$"]
[[hooks.pre-push]]
type = "shell"
when = "is_def_var(\"IssueNumber\")"
script = """
echo "Validating issue {{IssueNumber}}..."
curl -f "https://api.example.com/issues/{{IssueNumber}}" || exit 1
"""Example - With Environment Variables:
[[hooks.pre-commit]]
type = "shell"
env = { DATABASE_URL = "sqlite::memory:", LOG_LEVEL = "debug" }
script = "cargo test --features integration"Success/Failure:
- Success: Script exits with code 0
- Failure: Script exits with non-zero code
Use cases:
- Complex validation logic with multiple commands
- Scripts requiring shell features (pipes, conditionals)
- Integration with external services
- Multi-step validation processes
- Custom business logic
Rules for file system operations.
Writes content to a file, optionally appending to existing content.
Parameters:
-
path(required) - File path to write (relative to repository root) -
content(required) - Content to write to the file -
append(optional) - Iftrue, append to existing file; iffalseor omitted, overwrite the file
Example - Create Commit Template:
extract = ["branch?:^(?<IssueNumber>PROJ-\\d+)-.*$"]
[[hooks.post-checkout]]
type = "write-file"
when = "is_def_var(\"IssueNumber\")"
path = ".git/commit_msg_template.txt"
content = "{{IssueNumber}}: "Example - Clear Commit Template:
[[hooks.post-checkout]]
type = "write-file"
when = "!is_def_var(\"IssueNumber\")"
path = ".git/commit_msg_template.txt"
content = ""Example - Append to Log File:
[[hooks.post-commit]]
type = "write-file"
path = ".git/commit-log.txt"
content = "Committed at {{timestamp}}\n"
append = trueSuccess/Failure:
- Success: File is written successfully
- Failure: Cannot write file (permissions, invalid path, etc.)
Use cases:
- Update commit message templates dynamically
- Log hook executions
- Generate configuration files
- Update build metadata
- Create or modify Git configuration
Deletes files that match a glob pattern.
Parameters:
-
glob(required) - Glob pattern of files to delete -
fail-if-not-found(optional, defaultfalse) - Iftrue, fail when no files match
Example - Clean generated logs before commit:
[[hooks.pre-commit]]
type = "delete-files"
glob = "target/tmp/**/*.log"
fail-if-not-found = falseExample - Enforce removal of forbidden files:
[[hooks.pre-commit]]
type = "delete-files"
glob = "**/*.pem"
fail-if-not-found = trueSuccess/Failure:
-
Success: All matched files are removed; if
fail-if-not-foundis false, no matches still succeeds -
Failure: Deletion errors (permissions, invalid glob) or no matches when
fail-if-not-foundis true
Use cases:
- Prevent committing secrets or build artifacts
- Clean up generated files after scripts run
- Enforce workspace hygiene before pushing changes
Rules can be combined to create sophisticated workflows:
extract = ["branch?:^(?<IssueNumber>PROJ-\\d+)-.*$"]
# Require issue number in commit message if branch has one
[[hooks.commit-msg]]
type = "message-prefix"
when = "is_def_var(\"IssueNumber\")"
prefix = "{{IssueNumber}}: "
# Run integration tests only for feature branches
[[hooks.pre-push]]
type = "exec"
when = "is_def_var(\"IssueNumber\")"
command = "cargo"
args = ["test", "--features", "integration"]# Check branch name format
[[hooks.pre-push]]
type = "branch-name-regex"
regex = "^(feature|bugfix)/[a-z0-9-]+$"
# Check commit message format
[[hooks.commit-msg]]
type = "message-regex"
regex = "^(feat|fix):\\s.+"
# Run tests
[[hooks.pre-commit]]
type = "exec"
command = "cargo"
args = ["test"]
# Check formatting
[[hooks.pre-commit]]
type = "shell"
script = "cargo fmt --check"extract = [
"branch?:^(?<Team>[^/]+)/(?<Issue>[^/]+)/.*$",
"repo_path?:^/home/(?<Username>[^/]+)/.*$"
]
# Different rules based on team
[[hooks.pre-commit]]
type = "exec"
when = "is_def_var(\"Team\") && Team == \"frontend\""
command = "npm"
args = ["run", "test:ui"]
[[hooks.pre-commit]]
type = "exec"
when = "is_def_var(\"Team\") && Team == \"backend\""
command = "cargo"
args = ["test"]- Start with simple rules - Begin with basic validation before adding complex logic
- Use meaningful rule names - Comments help explain complex configurations
-
Test rules individually - Use
fisherman handle <hook>to test rules - Handle failures gracefully - Ensure error messages are clear and actionable
-
Use conditional execution - Avoid running unnecessary rules with
whenconditions - Leverage variables - Extract information once and reuse it across rules
- Keep scripts focused - Each rule should have a single, clear responsibility
- Consider performance - Minimize expensive operations in frequently-used hooks
- Document complex regex - Add comments explaining non-obvious patterns
- Use appropriate hooks - Match rules to the right Git hook for best results
- Check that the hook is configured for the correct Git hook
- Verify the
whencondition evaluates totrue - Ensure variables are extracted correctly
- Use
fisherman explain <hook>to see configured rules
- Check command exists and is in PATH
- Verify arguments are correct
- Review environment variables
- Test command manually outside Fisherman
- Ensure variables are extracted with
extract - Check variable names match regex named groups
- Verify variable is defined before using (use
whencondition) - Use
{{variable}}syntax, not${variable}
See Examples for more real-world use cases.
Copies one or more files matching a glob into a destination, preserving the relative path when a source directory is provided.
Parameters:
-
glob(required) - Glob pattern of files to copy -
destination(required) - Target directory (created if missing) -
source(optional) - Base directory to resolve the glob from; if omitted, the repository root is used
Example - Copy shared templates into the repo:
[[hooks.post-checkout]]
type = "copy-files"
glob = "templates/**/*.md"
source = "./scaffolding"
destination = "./docs"Example - Copy CI config with variables:
extract = ["branch?:^(?<Env>staging|prod)-.*$"]
[[hooks.post-checkout]]
type = "copy-files"
glob = "{{Env | default(\"staging\")}}/*.yml"
source = "./ci-presets"
destination = "./.github/workflows"Success/Failure:
- Success: Files are copied; output includes how many files were copied
- Failure: Glob resolution fails, permissions errors, or destination cannot be created
Use cases:
- Keep docs or boilerplate in sync across branches
- Drop environment-specific config after checkout
- Scaffold project files without manual copying
Rules for validating repository content. Typically used with pre-commit hooks.
Prevents committing files that match a glob pattern.
Parameters:
-
glob(required) - Glob pattern to check against staged files
Example - Prevent secrets:
[[hooks.pre-commit]]
type = "suppress-files"
glob = "*.secret"Success/Failure:
- Success: No staged files match the glob pattern
- Failure: One or more staged files match the glob pattern
Use cases:
- Prevent committing sensitive files, large binaries, or specific extensions.
Prevents committing changes that contain a specific string or regex pattern in the diff of added lines. Optionally, can be constrained to certain files using a glob pattern.
Parameters:
-
regex(required) - Regular expression pattern to search for in added diff lines -
glob(optional) - Glob pattern to restrict which staged files to inspect
Example - Check for TODOs:
[[hooks.pre-commit]]
type = "suppress-string"
regex = "(?i)TODO"Example - Check for console.log in JS/TS:
[[hooks.pre-commit]]
type = "suppress-string"
regex = "console\\.log"
glob = "**/*.{js,ts}"Success/Failure:
- Success: No newly added lines match the given regular expression pattern
- Failure: One or more newly added lines match the pattern
Use cases:
- Block debug statements (
console.log,debugger,print()) - Prevent committing "TODO" or "FIXME" comments
- Enforce strict content guidelines on newly written code