> For the complete documentation index, see [llms.txt](https://docs.sonarsource.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sonarsource.com/sonarqube-cli/integrations/git-hooks.md).

# Git hooks

Block commits and pushes that contain secrets with a Git hook installed and managed by the SonarQube CLI.

`sonar integrate git` installs secrets detection hooks that scan your code at commit or push time. By default the command installs globally: it writes hook scripts under `~/.sonar/sonarqube-cli/hooks/` and sets `git config --global core.hooksPath` to that directory, which makes every repository on this machine use them, unless a repo has its own local `core.hooksPath`. Pass `--local` to install the hook for this repository only, as a workaround when a global hook does not fit (for example, an existing Husky setup). See [Install for this repository only](#install-for-this-repository-only). Installed hooks delegate to the CLI's Git hook handlers (`sonar hook git-pre-commit` or `sonar hook git-pre-push`), which run secrets detection (and optionally dependency-risks scanning on pre-commit), with no extra tooling required. See [Add dependency-risks scanning to pre-commit](#add-dependency-risks-scanning-to-pre-commit) for the optional SCA scan.

In an interactive terminal, the command shows a **SonarQube Git Integration (source code scanning)** banner, warns that Git prioritizes a local `core.hooksPath` over the global one, and asks you to confirm before writing hooks. It then prompts you to install each code scanning hook (`pre-commit` and `pre-push`). Before writing hooks, it shows a [What will be installed](/sonarqube-cli/integrations/integrations.md#install-confirmation) summary and waits for you to press Enter.

Pass `--hook` to install a specific hook without the hook-type prompts, or `--non-interactive` to install without confirmation (see [Non-interactive install](#non-interactive-install)).

## Prerequisites

* [The SonarQube CLI is installed and authenticated](/sonarqube-cli/quickstart-guide.md).

## Choose pre-commit or pre-push

The CLI supports two hook types. Both stop a secret from leaving your machine, but at different moments:

| Hook         | Fires when…          | What it scans                                                           | Trade-off                                                                                  |
| ------------ | -------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `pre-commit` | You run `git commit` | Staged files for secrets; optionally dependency manifests for SCA risks | Catches secrets the earliest. Runs on every commit, which is slower for big change sets.   |
| `pre-push`   | You run `git push`   | Files changed in unpushed commits for secrets                           | Catches secrets just before they leave your machine. Lets you `git commit` freely locally. |

For most teams, `pre-commit` is the right default. It catches secrets before they enter local history. Choose `pre-push` if your developers commit constantly and want a single batched check before sharing.

## Install

```bash
# Interactive: prompts for pre-commit and pre-push separately
sonar integrate git

# Install a specific hook without hook-type prompts:
sonar integrate git --hook pre-commit
sonar integrate git --hook pre-push
```

In an interactive install, accept both hooks in one run. Also install them one at a time by running the command again with a different `--hook` value.

Globally-installed hooks live in `~/.sonar/sonarqube-cli/hooks/`. The CLI sets `git config --global core.hooksPath` to that directory, which makes every Git repo on your machine use them, unless a repo has its own local `core.hooksPath` (for example, Husky). If a project has a local `core.hooksPath`, the global hook does not run there. Either unset the local path with `git config --unset core.hooksPath` to let the global hook run, or pass `--local` to install the hook into that repository's existing setup. See [Install for this repository only](#install-for-this-repository-only).

A global install tells Git to look only at Sonar's hook directory instead of each repo's `.git/hooks/` folder. To avoid silently disabling hooks you already had there, the global Sonar hook script chains to any executable pre-existing local hook of the same name before running Sonar's own check. The local hook runs first; if it exits with a non-zero code, the commit or push aborts and Sonar's scan does not run. If the pre-existing hook is already a Sonar-installed hook (identified by a marker comment), the CLI skips chaining to avoid scanning twice. Chaining works from linked [git worktrees](https://git-scm.com/docs/git-worktree) as well as the main checkout. For `pre-push` hooks, the ref list on stdin is captured once and replayed to both the chained hook and Sonar's scan.

### Non-interactive install

```bash
# Without --hook: installs both pre-commit and pre-push
sonar integrate git --non-interactive

# Or pick one hook explicitly:
sonar integrate git --hook pre-commit --non-interactive
```

In non-interactive mode the CLI does not prompt for feature selection, install confirmation, or feature removal. Without `--hook` it installs both hook types. It fails fast on conflicts. Combine with `--force` to overwrite a pre-existing hook (see [How the CLI handles existing hooks](#how-the-cli-handles-existing-hooks)).

## Install for this repository only

Use `--local` when a global hook does not fit, for example a repository that already uses Husky or the pre-commit framework. This is a workaround, not the default. The CLI does not offer `--local` through any interactive prompt; you must pass the flag.

`-g` / `--global` is a compatibility flag. It has been deprecated since 1.9.0 and will be removed in a future version. The command already installs globally when you omit `--local`. Passing `--global` prints a warning and does not change the installation scope. `--global` and `--local` cannot be used together; that combination fails with an invalid-options error (exit code `2`).

```bash
# Interactive: still prompts for hook types; installs into this repository only
sonar integrate git --local

# Non-interactive: pre-commit only, this repository only
sonar integrate git --hook pre-commit --local --non-interactive
```

`--local` must run from inside a git repository. Outside one, the command fails with `No git repository found` and tells you to run it from a repository or omit `--local`.

The CLI detects how this repository already manages hooks and writes into that layout: Husky, the pre-commit framework, or native Git under `.git/hooks/`. It does not follow an inherited global or system `core.hooksPath`; it cannot overwrite the global hook from a prior `sonar integrate git`.

If Git would still prefer that inherited path over the directory `--local` writes to, the CLI warns and prints the override:

```bash
git config --local core.hooksPath <hooks-dir>
```

Until you set that override, the hook that `--local` writes will not run. Because Husky already sets a repo-local `core.hooksPath`, that warning does not appear for a typical Husky setup.

If a project key is auto-detected, `--local` bakes it into the generated hook. If none is detected, the CLI warns you to run `sonar link <projectKey>` to link a project to this repository. Dependency-risks scanning (when installed) then resolves the project at commit time. See [Project key auto-detection](/sonarqube-cli/integrations/integrations.md#project-key-auto-detection).

## Add dependency-risks scanning to pre-commit

Extend the `pre-commit` hook to run a Software Composition Analysis (SCA) scan on dependency manifest files in addition to the mandatory secrets scan. The scan uses the same engine as [Software Composition Analysis (SCA)](/sonarqube-cli/analysis/sca.md) and requires Advanced Security with SCA enabled on your SonarQube project.

Dependency-risks scanning is available only for `pre-commit` hooks. It is not supported on `pre-push` hooks.

### Install with dependency-risks

```bash
# Interactive: asks whether to enable dependency-risks when SCA is available
sonar integrate git

# Non-interactive: installs pre-commit (and pre-push) and enables dependency-risks when SCA is available
sonar integrate git --non-interactive

# Non-interactive: pre-commit only
sonar integrate git --hook pre-commit --non-interactive
```

In an interactive install, the CLI asks whether to enable dependency-risks scanning on the pre-commit hook when Software Composition Analysis (SCA) is available on your SonarQube connection. If SCA is not enabled, the prompt is skipped and only secrets scanning is installed. In non-interactive mode, the scan is enabled automatically when SCA is available.

The generated hook does not bake in a project key on a global install. At commit time, the hook resolves the key with [project key auto-detection](/sonarqube-cli/integrations/integrations.md#project-key-auto-detection). If no key resolves, the hook skips the dependency-risks stage, does not block the commit, and tells you to run `sonar link <projectKey>` to link a project to this repository. A `--local` install bakes in an auto-detected project key when one is found; see [Install for this repository only](#install-for-this-repository-only).

### Limitations

| Constraint                            | Reason                                                                                                                                                                                                                      |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pre-commit` only                     | Dependency-risks scanning runs on staged manifest files at commit time.                                                                                                                                                     |
| SCA must be enabled on the connection | The CLI checks SCA availability before offering or installing dependency-risks scanning. Same prerequisites as `sonar analyze dependency-risks`. See [Software Composition Analysis (SCA)](/sonarqube-cli/analysis/sca.md). |
| Project key resolved at commit time   | The hook needs a SonarQube project key to run SCA. Run `sonar link <projectKey>` or configure auto-detection (see [Project key auto-detection](/sonarqube-cli/integrations/integrations.md#project-key-auto-detection)).    |

### What the hook does

When dependency-risks scanning is enabled, the pre-commit handler:

1. Scans staged files for secrets (same as the default hook).
2. If any staged dependency manifest or lock file changed, runs a dependency-risks scan against your SonarQube project for **new** risks at `MEDIUM` severity or above (`BLOCKER`, `HIGH`, and `MEDIUM`).
3. Blocks the commit when matching risks are found.

The hook skips the dependency-risks stage when no manifests changed, when the SCA scanner binary is not installed, when no project key resolves, or when the scan cannot complete (for example, a network error). In those cases the commit is not blocked. When the SCA scanner binary is missing, the hook prints a warning that names the skip and tells you to re-run `sonar integrate git` to restore it. When no project key resolves, the hook tells you to run `sonar link <projectKey>` to link a project to this repository. When the scan completes with no new risks, the hook prints a brief success line (`No dependency risks found.`). When risks are found, the hook blocks the commit with a minimal summary (for example, `3 dependency risks found (1 BLOCKER, 2 HIGH)`) and points you to `sonar analyze dependency-risks -p <YourProjectKey>` for the full table, fix recommendations, and details. Use `git commit --no-verify` to bypass if the risks are already reviewed.

## Runtime requirements

Installed Git hooks delegate to `sonar hook git-pre-commit` or `sonar hook git-pre-push`. At runtime, both require:

* An authenticated CLI session (`sonar auth login` or valid [environment variables](/sonarqube-cli/using-sonarqube-cli/environment-variables.md))
* The `sonar-secrets` analyzer binary under `~/.sonar/sonarqube-cli/bin/`

If either prerequisite is missing, the hook blocks the commit or push (exit code `1`) and prints a remediation message instead of silently skipping the scan. This matches the fail-closed behavior of agent secrets hooks (see [When scanning is inactive](/sonarqube-cli/analysis/secrets-detection.md#when-scanning-is-inactive)).

> **Note:** Dependency-risks scanning on `pre-commit` follows different rules when its own binary is missing; see [Add dependency-risks scanning to pre-commit](#add-dependency-risks-scanning-to-pre-commit).

## How the CLI handles existing hooks

### Global installs chain to local hooks

Any executable hook already in `.git/hooks/<name>` is invoked automatically before Sonar's check. You do not need `--force` for this case, the local file stays in place and the global script delegates to it. See [Install](#install).

If a hook already exists in `~/.sonar/sonarqube-cli/hooks/` and was not installed by `sonar integrate git`, the command refuses to overwrite it. Pass `--force` to overwrite:

```bash
sonar integrate git --force
```

A marker comment identifies the hook, letting subsequent `sonar integrate git` runs recognize and update it without `--force`.

### Local installs

If a hook already exists in the repository location `--local` would write to (`.git/hooks/`, Husky, or `.pre-commit-config.yaml`) and was not installed by `sonar integrate git`, the command refuses to overwrite it. Pass `--force` to overwrite.

If an earlier CLI version installed per-repo hooks (plain Git, Husky, or the pre-commit framework), those files are not removed by a later global install or by a CLI upgrade. The agent-integration migration does not touch Git. Remove them manually if you no longer want the duplicate scan; see [Uninstall](#uninstall).

## Verify the hook

1. Create a file with a fake-looking but secret-shaped value:

   ```javascript
   // secrets.js
   const API_KEY = "sqp_1aa323ae0689cd4a1abd062a2ad0a224ae8a1d13";
   ```
2. Stage and try to commit:

   ```bash
   git add secrets.js
   git commit -m "Test"
   ```
3. The commit should be blocked and the secret reported.

Delete the test file once confirmed.

## Bypass the hook

If you need to skip the hook for a single commit (for example, while running a script that the hook would interfere with), use Git's built-in `--no-verify` flag:

```bash
git commit --no-verify
```

> **Warning:** Use `--no-verify` sparingly. The whole point of the hook is to catch secrets before they enter your history. Prefer fixing the offending file over bypassing the check.

## Uninstall

Re-run `sonar integrate git` in an interactive terminal. For each installed hook feature, decline **Keep?** and confirm **Proceed with removal?** to tear down the hook and prune state. See [integrations/README.md](/sonarqube-cli/integrations/integrations.md#removing-installed-features).

To remove the hook manually:

* Unset the global hooks path with `git config --global --unset core.hooksPath` and delete the directory at `~/.sonar/sonarqube-cli/hooks/`.
* If you used `--local`, or an earlier CLI version installed per-repo hooks, also delete `.git/hooks/pre-commit` and `.git/hooks/pre-push` if they were installed by the CLI, or remove the SonarQube entry from your Husky scripts or `.pre-commit-config.yaml`. The CLI marks its hooks with a comment, which lets you identify them.

See [Uninstalling](/sonarqube-cli/administration/uninstall.md) for the full removal procedure.

## Related pages <a href="#related-pages" id="related-pages"></a>

* [Secrets detection](/sonarqube-cli/analysis/secrets-detection.md)
* [Software Composition Analysis (SCA)](/sonarqube-cli/analysis/sca.md)
* [Claude Code](/sonarqube-cli/integrations/claude-code.md)
* [GitHub Copilot CLI](/sonarqube-cli/integrations/github-copilot-cli.md)
* [Exit codes](/sonarqube-cli/using-sonarqube-cli/exit-codes.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.sonarsource.com/sonarqube-cli/integrations/git-hooks.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
