# Getting started

By the end of this page you will have Commit Check installed, rejecting a bad
commit message on your machine, and wired into the two places it belongs.

It takes about five minutes and needs nothing but a Git repository.

!!! tip "On GitHub? The App needs no local setup"

    [Install the GitHub App](https://github.com/apps/commit-check) on the
    repositories you want checked: every push to a branch and every pull request
    in them gets a **Commit Check** result, with no workflow file. The
    [App guide](guides/github-app.md) covers what it checks. This page sets up
    the CLI and the hook, which work with any Git host.

## 1. Install

=== "pip"

    ```console
    $ pip install commit-check
    ```

=== "uv"

    ```console
    $ uv tool install commit-check
    ```

=== "pipx"

    ```console
    $ pipx install commit-check
    ```

Verify the install:

```console
$ commit-check --version
```

The CLI is also available as `cchk`, which is the same program under a shorter
name.

!!! tip "Supported Python versions"

    Commit Check supports Python 3.10 through 3.15, on Linux, macOS and Windows.

Running it as a [pre-commit hook](guides/pre-commit.md)
or a [GitHub Action](guides/github-actions.md) needs no
installation step at all — both fetch it for you.

## 2. Watch it reject something

Commit Check works with no configuration at all. Make a deliberately bad commit
in a scratch repository:

```console
$ git init demo && cd demo
$ git commit --allow-empty -m "updated the parser"
```

Now check it:

```console
$ commit-check --message
```

```text
CC001 message check failed ==> updated the parser
The commit message should follow Conventional Commits. See https://www.conventionalcommits.org
Suggest: Use <type>(<scope>): <description>, where <type> is one of: feat, fix, docs, ...
Docs: https://commit-check.com/rules/#cc001
```

Four things are happening in that output, and each is deliberate:

| Part | What it gives you |
|---|---|
| `CC001` | A stable rule ID. It will mean the same thing in five years. |
| `==> updated the parser` | The exact value that failed, not just "invalid message". |
| `Suggest:` | What to do about it. |
| `Docs:` | Why the rule exists, and how to configure or disable it. |

## 3. Fix it

```console
$ git commit --amend --allow-empty -m "fix(parser): handle empty input"
$ commit-check --message
```

It prints nothing and exits with code `0`.

## 4. Check the branch too

```console
$ git switch -c my-changes
$ commit-check --branch
```

```text
CC201 branch check failed ==> my-changes
The branch should follow Conventional Branch. See https://conventionalbranch.org
Suggest: Use <type>/<description> with an allowed type, or add the branch to allow_branch_names in config
Docs: https://commit-check.com/rules/#cc201
```

Rename it to something structured and it passes:

```console
$ git branch -m fix/empty-input
$ commit-check --branch
```

!!! tip "Checks are opt-in per run"

    `commit-check --message` never evaluates branch rules, and vice versa. Each
    check is selected by its own flag, so you can run exactly what a given hook
    or CI job needs. The [rules reference](rules.md) lists which flag activates
    each rule.

## 5. Write down your policy

So far you have been running the defaults. Create a `cchk.toml` in the
repository root — or in `.github/` — to make the policy explicit:

```toml title="cchk.toml"
[commit]
conventional_commits = true
subject_imperative = true          # (1)
subject_max_length = 72
allow_wip_commits = false          # (2)

[branch]
conventional_branch = true
```

1. Off by default. Turning it on rejects `fixed a bug` in favour of `fix a bug`.
2. `allow_*` options describe what is *permitted*. Set to `false` to enforce.

Run it again and the new rules apply:

```console
$ commit-check --message
```

!!! warning "Defaults are not "nothing""

    Even with no config file, Conventional Commits, Conventional Branch, subject
    length limits of 5–80 characters, and author name/email patterns are
    enforced. Check the *Default* column in the [rules reference](rules.md)
    before assuming a rule is off.

## 6. Make it automatic

Running the command by hand does not scale. Wire it into the two places it
belongs:

<div class="grid cards" markdown>

-   :lucide-git-commit-horizontal:{ .lg .middle } __Before the commit lands__

    ---

    A pre-commit hook rejects the message as you write it, so nothing bad
    reaches the branch in the first place.

    [:lucide-arrow-right: Pre-commit hook](guides/integrations.md#as-a-pre-commit-hook)

-   :brand-github:{ .lg .middle } __On every pull request__

    ---

    A GitHub Action checks every commit in the PR and can comment on the PR
    with what needs fixing.

    [:lucide-arrow-right: GitHub Actions](guides/integrations.md#in-github-actions)

</div>

## Verifying the download

Every release is published with a signed
[build provenance attestation](https://docs.github.com/en/actions/concepts/security/artifact-attestations). To verify
a release artifact came from this repository's build pipeline:

```console
$ gh attestation verify commit_check-*.whl --repo commit-check/commit-check
```

## Show that you use it

Put the badge in your README, so contributors know their commits will be
checked before they open a pull request:

[![commit-check](badge.svg)](https://commit-check.com)

=== "Markdown"

    ```markdown
    [![commit-check](https://commit-check.com/badge.svg)](https://commit-check.com)
    ```

=== "reStructuredText"

    ```rst
    .. image:: https://commit-check.com/badge.svg
       :target: https://commit-check.com
       :alt: commit-check
    ```

## Where to go next

- **[Where to run it](guides/integrations.md)** — pre-commit hook, GitHub
  Action, GitHub App: which to use, and how they combine.
- **[Rules reference](rules.md)** — every rule, what it does, why it matters,
  and how to configure it.
- **[Configuration](configuration.md)** — every option, its type and default,
  plus the environment variable and CLI flag that override it.
- **[Command-line recipes](example.md)** — checking a range, wiring up CI,
  reading the JSON output.
- **[Troubleshooting](troubleshoot.md)** — a check failing that you did not
  turn on, nothing running at all, and how to get a commit through when you
  have to.
