Skip to content

feat: filter reviews by commit author, date, message and branch - #25

Merged
muhammetsafak merged 1 commit into
mainfrom
feature/commit-level-filters
Jul 26, 2026
Merged

feat: filter reviews by commit author, date, message and branch#25
muhammetsafak merged 1 commit into
mainfrom
feature/commit-level-filters

Conversation

@muhammetsafak

Copy link
Copy Markdown
Member

git diff has no --author/--since/--until/--grep — those are git log options — so a filter that selects commits cannot ride the normal diff-acquisition path. Add a commit-selection layer behind the existing fetchDiff seam, plus the path denylist that was missing next to --file/--dir.

New global flags:

--author / --committer name or email, case-insensitive; repeatable
--start-date/--end-date strict YYYY-MM-DD, both ends inclusive
--text commit message, and branch names
--max-commits / --merges modifiers; error if used alone
--exclude-file/--exclude-dir path denylist, --file/--dir rules inverted

AND across filter kinds, OR within one kind.

internal/git/select.go runs a two-phase select-then-show: a git log metadata walk, an optional for-each-ref + rev-list pass for branch-name hits, then git show -m --first-parent for exactly the chosen hashes.

Three decisions worth recording:

  • Identity and text matching happen in Go, not git. git log --author=A --grep=B ORs the two by default, and --all-match would then also AND multiple --author values together, breaking OR-within-a-kind.
  • git show, not git log -p. The latter indents the commit body four spaces, and internal/diff's parser reads a leading-space line as hunk context, so a message body would be silently absorbed into the previous hunk.
  • The patches are concatenated, not reduced to one cumulative A..B diff. A cumulative diff would include every unmatched commit in between, making the filter a lie. The cost is that a file touched by three matching commits appears three times.

--end-date is expanded to 23:59:59 so the named day is included; git's bare --until stops at that day's midnight and drops it.

Scope: no positional range walks HEAD, bounded by --max-commits; a subcommand's range bounds it instead. Conflicts with --staged/--unstaged, which have no commits. Rejected by commit (describes the staged index) and remote pr (its diff comes from gh pr diff).

Also carries the filters across the MCP/guard seam, which resets the global flag state — this makes --file/--dir reachable there for the first time. Adds meta.filtered_commits (omitempty, schema stays 1) and commit/exclusion accounting to dry-run. No cache-key change: the key already hashes the post-filter diff text.

Fixes: remote pr now applies --file/--dir on the posting path too, not only under --no-post.

Docs: ADR-0035, contracts/{cli-surface,json-schema-v1,cache-key}, TECHNICAL_ARCHITECTURE, architecture/{overview,diagrams}, PRD, README, CHANGELOG, man pages.

Summary

Related issues

Type of change

  • Bug fix (non-breaking)
  • New feature (non-breaking)
  • Breaking change (behavior or API)
  • Documentation only
  • Refactor / cleanup (no behavior change)
  • Build / release / CI

Test plan

  • make lint test passes locally
  • Added or updated tests for the new behavior
  • Manually verified the affected commands in a real repo

Notes for reviewers

Checklist

  • I have read the Contributing guide.
  • My contribution is licensed under GPL-3.0-or-later (inbound = outbound).
  • User-facing strings use internal/i18n (no hard-coded text).
  • If this changes user-visible behavior, the README / man page / commitbrief list output has been updated accordingly.

`git diff` has no --author/--since/--until/--grep — those are `git log`
options — so a filter that selects commits cannot ride the normal
diff-acquisition path. Add a commit-selection layer behind the existing
`fetchDiff` seam, plus the path denylist that was missing next to
--file/--dir.

New global flags:

  --author / --committer   name or email, case-insensitive; repeatable
  --start-date/--end-date  strict YYYY-MM-DD, both ends inclusive
  --text                   commit message, and branch names
  --max-commits / --merges modifiers; error if used alone
  --exclude-file/--exclude-dir  path denylist, --file/--dir rules inverted

AND across filter kinds, OR within one kind.

internal/git/select.go runs a two-phase select-then-show: a `git log`
metadata walk, an optional for-each-ref + rev-list pass for branch-name
hits, then `git show -m --first-parent` for exactly the chosen hashes.

Three decisions worth recording:

- Identity and text matching happen in Go, not git. `git log --author=A
  --grep=B` ORs the two by default, and --all-match would then also AND
  multiple --author values together, breaking OR-within-a-kind.
- `git show`, not `git log -p`. The latter indents the commit body four
  spaces, and internal/diff's parser reads a leading-space line as hunk
  context, so a message body would be silently absorbed into the
  previous hunk.
- The patches are concatenated, not reduced to one cumulative A..B diff.
  A cumulative diff would include every unmatched commit in between,
  making the filter a lie. The cost is that a file touched by three
  matching commits appears three times.

--end-date is expanded to 23:59:59 so the named day is included; git's
bare --until stops at that day's midnight and drops it.

Scope: no positional range walks HEAD, bounded by --max-commits; a
subcommand's range bounds it instead. Conflicts with --staged/--unstaged,
which have no commits. Rejected by `commit` (describes the staged index)
and `remote pr` (its diff comes from `gh pr diff`).

Also carries the filters across the MCP/guard seam, which resets the
global flag state — this makes --file/--dir reachable there for the
first time. Adds meta.filtered_commits (omitempty, schema stays 1) and
commit/exclusion accounting to dry-run. No cache-key change: the key
already hashes the post-filter diff text.

Fixes: `remote pr` now applies --file/--dir on the posting path too, not
only under --no-post.

Docs: ADR-0035, contracts/{cli-surface,json-schema-v1,cache-key},
TECHNICAL_ARCHITECTURE, architecture/{overview,diagrams}, PRD, README,
CHANGELOG, man pages.
@muhammetsafak
muhammetsafak merged commit 42fa087 into main Jul 26, 2026
9 checks passed
@muhammetsafak
muhammetsafak deleted the feature/commit-level-filters branch July 26, 2026 05:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant