// docs · v1.x

Review scopes

How to scope a CommitBrief review — staged, unstaged, arbitrary diff ranges, commit-level filters by author and date, path allow/deny filters, and the three-layer ignore pipeline.

A review needs a diff. CommitBrief gives you four sources for that diff plus two layers of filtering on top.

The default — staged changes

commitbrief
commitbrief --staged   # explicit
commitbrief -s         # short form

Reviews git diff --cached. This is the default when no scope flag is set — picked because it lines up with the pre-commit moment.

Working-tree changes

commitbrief --unstaged
commitbrief -u

Reviews git diff (working tree vs the index). Useful when you have edits you have not staged yet.

--staged and --unstaged are mutually exclusive — passing both is a cobra-level error before any work begins.

Historic ranges — commitbrief diff

For anything outside the working tree, use the diff subcommand. The positional arguments are forwarded verbatim to git diff --no-color --no-ext-diff <args>, so anything git diff accepts works.

Invocation Equivalent What it reviews
commitbrief diff HEAD git diff HEAD Working tree vs HEAD.
commitbrief diff HEAD~3 HEAD git diff HEAD~3 HEAD The last three commits’ net change.
commitbrief diff main feature git diff main feature One branch vs another.
commitbrief diff main...feature git diff main...feature Three-dot range — feature’s changes since branching off main (PR style).
commitbrief diff <merge-sha> git diff <merge-sha> First-parent diff of a merge commit.
commitbrief diff HEAD -- '*.go' git diff HEAD -- '*.go' Filter by git pathspec after --.

At least one positional argument is required.

Commit filters (v1.15.0)

The three scopes above all produce one diff. Commit filters produce a set of commits instead — “everything Alice touched since June”, “every commit whose message mentions payment” — and review the concatenation of their patches (ADR-0035).

git diff has no author or date options; those are git log options. So setting any of these flags switches diff acquisition to a commit walk, which is why they cannot be combined with --staged / --unstaged: the index has no commits yet.

Flag Matches
--author author name or email, case-insensitive substring; repeatable, OR’d
--committer committer name or email; repeatable, OR’d
--start-date YYYY-MM-DD author date on or after this day (inclusive)
--end-date YYYY-MM-DD author date on or before this day (inclusive — unlike git’s bare --until, which stops at that day’s midnight and silently drops it)
--text the commit message, plus commits unique to a branch whose name contains the text
commitbrief --author alice --author bob            # either person's commits
commitbrief --author [email protected]             # name or email
commitbrief --start-date 2026-01-01                # on or after (inclusive)
commitbrief --text payment                         # message OR branch name
commitbrief diff main..develop --author alice      # bound the walk to a range

Different kinds are AND’d, multiple values of one kind are OR’d: --author alice --author bob --start-date 2026-06-01 means “(Alice or Bob) and since June”.

The revision range walked is HEAD by default, or the range you give a subcommand. The resulting diff is the concatenation of the matching commits’ patches, not a cumulative range diff — so a file changed in three of them appears three times, and no unmatched commit’s work leaks in.

Branch-name matching is best-effort by nature: a squash- or rebase-merged branch no longer owns its commits, so nothing will be found for it.

Two modifiers

--max-commits N (default 200) caps the selection and always reports truncation rather than silently reviewing a subset. --merges keeps merge commits, which the walk excludes by default. Neither starts a walk — passing one on a review with no commit filter set is a usage error, since there is nothing to modify. (On leaks and map, which always walk history, --max-commits is an ordinary bound.)

Where they apply

Available on the default review, diff, summary, dry-run, the MCP review tool, guard, leaks, and map.

They are rejected by commit, which describes the staged index and therefore has no commits, and by remote pr, whose diff comes from gh pr diff rather than local git.

commitbrief map --author alice is the fastest way to check a filter before paying for a review — it draws the graph with the matches highlighted and the rest dimmed as context.

Path filters — --file and --dir

Repeatable filter flags that compose on top of any scope:

commitbrief --staged -f src/main.go -f src/util.go
commitbrief --unstaged -d database/seeder -d app/Models
commitbrief diff HEAD~3 HEAD --dir docs
  • --file <path> (-f) matches a file path exactly (the diff’s b/ path relative to repo root). Renamed files match on either the new path or the old path.
  • --dir <path> (-d) matches any file whose path begins with the given directory plus a slash. database/seed does not match database/seedother/*.
  • Both flags repeat. Multiple instances are unioned — a file matching any one of them is kept.
  • They combine: --file foo.go --dir handlers/ keeps foo.go AND everything under handlers/.

Path filters apply after the ignore layers below.

Glob patterns (v1.7.0)

Both flags also accept gitignore-style glob patterns, not just exact paths (ADR-0026). A value containing *, ?, or [ is compiled as a glob; the slash decides how it anchors:

  • Slash-less patterns match the basename at any depth--file '*.go' keeps every changed .go file, anywhere in the tree.
  • Slash-bearing patterns are anchored to the repo root--file 'internal/**/*.ts' matches only under internal/, and --dir 'app/**' scopes to the app/ subtree.
commitbrief --staged --file '*.go'                 # any Go file, any depth
commitbrief --staged --file 'internal/**/*.ts'     # root-anchored
commitbrief diff main...feature --dir 'app/**'     # globbed directory scope

Quote the pattern so your shell doesn’t expand * before CommitBrief sees it.

Backward compatible: a value with no glob metacharacter keeps its exact pre-v1.7 behavior — --file src/main.go still matches that one path (and its rename pair). An invalid glob errors clearly up front instead of silently mis-filtering.

Denylists — --exclude-file and --exclude-dir (v1.15.0)

The inverse of --file / --dir. They share the exact same matching rules — literal path or gitignore-style glob — and are applied after the allowlist, so an exclusion always wins:

commitbrief --staged --exclude-file '*_test.go'    # everything but tests
commitbrief --staged --dir internal --exclude-dir internal/cli
commitbrief diff main...feature -d 'app/**' --exclude-file '*.generated.ts'

Both repeat, both accept globs, and an invalid pattern errors before any provider call — same as the allowlist.

Use the pair when the set you want is “this subtree, minus one corner of it”. Reaching for .commitbriefignore instead makes the exclusion permanent and team-wide; these flags are per-run.

The three-layer filter pipeline

The full pipeline that decides which files reach the LLM:

  1. Built-in ignore patterns — hardcoded into the binary. Lock files (*.lock, go.sum, package-lock.json, …), vendored code (vendor/**, node_modules/**), generated code (*.pb.go, *.gen.go), mocks, build artefacts, editor detritus, and binary blobs (*.png, *.zip, *.pdf).
  2. .commitbriefignore — repo-local gitignore-syntax overlay. Drop a file at the repo root. Glob syntax is the same as .gitignore; *, **, and a leading ! to re-include a previously-excluded path all work.
  3. --file / --dir path allowlists from the command line, then --exclude-file / --exclude-dir denylists on top of whatever survived.

Later layers can override earlier ones. To force review on a path the built-in layer would exclude:

# .commitbriefignore
!vendor/**

The ! re-inclusion overrides the built-in vendor/** pattern.

Inspecting filter behavior

commitbrief dry-run reports the per-layer counts:

Commits (walked):  50
Commits (matched): 12
Files (input): 12
  built-in ignore filtered:        3
  .commitbriefignore net filtered: 1
  --file/--dir path filter:        2
  --exclude-file/--exclude-dir:    1
Files (review): 5

A negative .commitbriefignore net filtered means a !pattern reverted a built-in exclusion. The two Commits lines appear only when a commit filter made the run walk history; commitbrief map shows which commits those were.

Mutually exclusive scope flags

Cobra enforces these mutex groups before any pipeline work runs:

Mutually exclusive Why
--staged × --unstaged Two scopes for the same run is ambiguous.
--staged / --unstaged × any commit filter A commit filter walks history; the index has no commits.
--provider × --cli Only one backend can serve a review.
--cli × --json × --markdown CLI providers emit pre-formatted plain text; you cannot also ask for JSON.

See also