How to use git pre-commit and pre-receive hooks to boost productivity
How to use Git pre-commit and pre-receive hooks to boost productivity
“Nobody is perfect” is not just a saying; it’s the truth. Some of your team may consider themselves close to perfect (scary, right?), but most of us know that small mistakes happen all the time.
The earlier we catch them, the better. Git pre-commit hooks run locally before a commit is created, while pre-receive hooks run on the remote Git server before a push updates repository references. Both can catch avoidable problems before they travel further through the development process.
They do different jobs, though—and neither is a replacement for continuous integration (CI), code review or testing.

What’s the difference between pre-commit and pre-receive hooks?
| Hook | Where it runs | When it runs | Typical use |
|---|---|---|---|
| Pre-commit | On a developer’s machine | Before git commit completes | Formatting, linting and fast local checks |
| Pre-receive | On the remote Git server | Before a pushed reference update is accepted | Server-enforced policies such as rejecting force pushes or invalid commit metadata |
A pre-commit hook can reject a commit when a check fails, but developers can bypass it with git commit --no-verify (or disable their local hook setup). A pre-receive hook is enforced by the remote server, where that feature is supported. Git’s official hooks documentation explains both.
What tools should run as pre-commit hooks?
1. Code formatters
Tools such as Prettier help keep code formatting consistent. At Izymes, we once spent the better half of a Friday pub lunch debating whether the maximum line length should be 160 or 80 characters. We settled on 100!
Commit your formatting configuration (for example, .prettierrc) to the repository so everyone uses the same rules. For a quick pre-commit check, run the formatter only on files being committed, rather than needlessly checking the entire project every time.

2. Linters
Linters such as ESLint examine source code for patterns that may signal bugs, inconsistencies or violations of agreed coding rules. They complement formatters: a formatter handles how code looks, while a linter can help flag potential code problems.
Keep the ruleset in version control. Choose checks that run quickly enough that developers won’t be tempted to skip them.
3. Static code analysis
Deeper analysis tools can detect possible security, reliability and maintainability issues. SonarQube Cloud (formerly SonarCloud) is one option for continuous analysis, often better run in CI or as part of pull-request checks than on every local commit.
The original article also mentioned LGTM.com. That service closed in December 2022, so it should no longer be recommended as an active tool.

4. A quick local build or test (optional)
A fast unit-test suite or compilation check can be useful before committing. Avoid making every commit wait for a slow full build; run expensive integration, security and deployment checks in CI instead. A pre-commit hook is the local place for this kind of quick test, not a substitute for a server-side pre-receive policy.
Get started: Set up a Git pre-commit hook with Husky
For an existing Node.js/JavaScript project with a package.json, Husky makes local Git hooks easy to configure. The old husky-init / husky add commands in the 2022 version of this article have changed.
1. Install Husky, Prettier and lint-staged:
npm install --save-dev husky prettier lint-staged
npx husky init
Husky’s init command creates .husky/pre-commit and adds a prepare script to package.json.
2. Edit .husky/pre-commit so its contents are:
npx lint-staged
3. Add this lint-staged configuration as a top-level property in your existing package.json (merge it into the existing file; don’t replace your package details):
"lint-staged": {
"*.{js,jsx,ts,tsx,json,md,css}": "prettier --write"
}
This example automatically formats staged files of those types when you commit, and lint-staged adds its formatting changes to the commit. Adjust the file types for your project; add a .prettierrc and .prettierignore as needed. For example, a .prettierrc could contain { "printWidth": 100 }—our hard-won Friday pub-lunch compromise.
4. Try it. Stage a changed, supported file and run git commit. Husky invokes lint-staged before completing the commit. Commit the .husky folder, package.json, lockfile and formatting configuration so teammates can use the same setup after installing dependencies.
For larger teams, also run npx prettier . --check in CI. Local hooks can be bypassed or not installed, so a passing local hook is not a guaranteed shared-repository policy. See the maintained Husky setup guide and Prettier installation guide.
What about Git pre-receive hooks in Bitbucket?
Unlike Husky, a pre-receive hook runs on the Git server, not on a developer’s laptop. It receives details of proposed reference updates and can reject an entire push if a configured policy is violated.
Bitbucket Data Center: Administrators can enable supported repository hooks at project or repository level. Built-in examples include rejecting force pushes, verifying signed commits and checking committer identity. Additional custom behaviour may require an appropriate Bitbucket app/plugin or administrator-developed integration. Don’t assume that putting a script in a local .git/hooks/ folder installs a server-side hook in managed Bitbucket Data Center.
Bitbucket Cloud: You cannot install arbitrary custom server-side Git pre-receive scripts. Local hooks still work, but each developer must have them installed and enabled. For centrally enforced repository policies, use the relevant branch restrictions and merge checks, plus CI checks where appropriate. These are alternatives for enforcing particular workflows—not identical replacements for custom pre-receive scripts.
It’s also worth distinguishing a pre-receive check when code is pushed from a pull-request merge check. One governs Git reference updates at the server; the other governs whether a reviewed change is allowed to merge under the repository’s configured rules.
Conclusion: Catch small mistakes early—and enforce important rules centrally
Pre-commit hooks are an easy way to catch formatting and linting problems while you’re still working locally. Pre-receive hooks, where available, can enforce policies on pushes to the shared repository. CI and pull-request reviews complete the picture.
Start with a quick check that saves your team time, keep it fast, and make sure the important rules are also enforced where they cannot be skipped. Happy coding!
Sean Manwarring
Izymes
Want more control over Bitbucket pull request reviews and merges?
Git hooks handle local checks and, on supported servers, push policies. If your team also needs reviewer assignment, approval quotas or configured merge conditions, explore Workzone for Bitbucket on the Atlassian Marketplace. Workzone helps manage the pull-request review/merge stage; it doesn’t replace Husky, CI or custom Git pre-receive hooks.
For related guidance, see Optimizing Your Pull Request Review and Merge Process: 3 Key Factors to Consider.
By Sean Manwarring, Head of Marketing at Izymes
Published 26 October 2022 · Updated 26 October 2026