fix: integrate git hooks with pre-commit - #17
Conversation
Enables validation of commit messages before the git object exists, allowing gitlance to work as a commit-msg hook. Comment lines are ignored, matching how a commit message is interpreted. The new mode/argument is mutually exclusive with the ref-based options (--base, --head, --repo, --skip-merge-commits), which are only meaningful when validating existing commits. Signed-off-by: Andrei Gherzan <andrei.gherzan@canonical.com>
When pushing a new branch, the pre-push hook derived its base from a single remote's HEAD. If that remote was behind (e.g. a fork whose main is a stale copy of upstream), it re-validated commits already reviewed and merged elsewhere, and could reject a push over commits the author never touched. Base validation on every remote-tracking ref instead: a commit already present on any remote has been published and does not need rechecking. Excluding a set of refs rather than a single base also lets the root commit be validated, which a single exclusive base can never reach. Closes: canonical#10 Signed-off-by: Andrei Gherzan <andrei.gherzan@canonical.com>
8d6cf24 to
4f9098f
Compare
|
Thanks for the feedback @agherzan. I’ve updated the branch on top of #13, which includes #12, and limited my commit to the pre-commit integration. I also expanded the commit message to include the implementation rationale and validation details. All checks are passing locally. Ready for another review when you have time. |
agherzan
left a comment
There was a problem hiding this comment.
Any reason not use the pre-commit install directly? I'm not sure I understand why you need the changes in gitlance.
Some small extra comments:
- keep git log lines at resonable lengths.
- SOB should have your name and email
|
Thanks, that makes sense. I added the Gitlance changes only to translate pre-commit's pre-push environment variables, but after rechecking #12 and #13, I agree this can be simpler. I'll use I'll also wrap the commit message at reasonable line lengths and update the author and sign-off to: |
4f9098f to
ee632a6
Compare
|
Updated as discussed. The contribution commit now uses I also wrapped the commit message at 72 columns and updated both the author and sign-off to |
There was a problem hiding this comment.
Pull request overview
This PR introduces pre-commit–based installation and configuration for local Git hooks, and extends the gitlance CLI to support commit-msg style validation (message-file mode) and pre-push style validation of only unpublished commits (not-on-remotes mode).
Changes:
- Add
--message-fileand--not-on-remotesCLI modes and supporting git utilities (remote_tracking_refs,get_commits_excluding). - Add integration/units tests covering message-file mode and not-on-remotes commit selection.
- Add pre-commit configuration + Taskfile/docs updates to install hooks via
pre-commit installand document install/uninstall behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration_tests.rs | Refactors test harness and adds integration coverage for --message-file and --not-on-remotes. |
| Taskfile.yml | Switches install-githooks to pre-commit install with preconditions. |
| src/main.rs | Adds CLI flags and implements message-file + not-on-remotes commit selection flow. |
| src/lib.rs | Re-exports new git APIs used by the CLI and other crates. |
| src/git.rs | Adds commit creation from message files, comment stripping, remote-tracking ref listing, and exclude-based revwalk selection. |
| README.md | Documents direct CLI usage for message-file and not-on-remotes modes. |
| githooks/pre-push | Updates hook behavior for new-branch pushes to use not-on-remotes logic. |
| githooks/commit-msg | Adds a standalone commit-msg hook script invoking --message-file. |
| CONTRIBUTING.md | Documents local hook installation via pre-commit and uninstall behavior. |
| .pre-commit-config.yaml | Adds pre-commit hooks for commit-msg and pre-push stages using gitlance. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| stages: [commit-msg] | ||
| - id: gitlance-pre-push | ||
| name: Validate commits with gitlance | ||
| entry: gitlance --head HEAD --not-on-remotes |
There was a problem hiding this comment.
This is fair. Same for the above.
There was a problem hiding this comment.
Good catch. I replaced the hardcoded HEAD with a small pre-commit adapter that reads PRE_COMMIT_TO_REF, falling back to PRE_COMMIT_LOCAL_BRANCH or HEAD, and skips non-branch refs. This handles git push origin otherbranch without changing the Gitlance Rust code. I validated the non-checked-out branch path, tag skipping, and the installed pre-push hook.
ee632a6 to
266711e
Compare
| hooks: | ||
| - id: gitlance-commit-msg | ||
| name: Validate commit message with gitlance | ||
| entry: gitlance --message-file |
There was a problem hiding this comment.
I would use the existing hook. Any disadvantages to that?
There was a problem hiding this comment.
No functional disadvantage here. Pre-commit passes the commit-message filename as the first argument, which matches what the existing githooks/commit-msg script expects. I used the binary directly to avoid an extra shell layer, but reusing the existing hook is clearer and avoids duplicating its behavior. I'll switch this entry to the existing hook.
| stages: [commit-msg] | ||
| - id: gitlance-pre-push | ||
| name: Validate commits with gitlance | ||
| entry: gitlance --head HEAD --not-on-remotes |
There was a problem hiding this comment.
This is fair. Same for the above.
| entry: gitlance --head HEAD --not-on-remotes | ||
| language: system | ||
| stages: [pre-push] | ||
| always_run: true |
There was a problem hiding this comment.
Could you explain why you added this?
There was a problem hiding this comment.
Gitlance validates commits rather than files, so this keeps the hook running for pushes with no changed files, such as an empty commit.
| language: system | ||
| stages: [pre-push] | ||
| always_run: true | ||
| pass_filenames: false |
There was a problem hiding this comment.
Could you explain why you added this?
There was a problem hiding this comment.
The adapter gets the pushed ref from pre-commit's environment. Changed filenames are not inputs to Gitlance, so they should not be passed.
| preconditions: | ||
| - sh: pre-commit --version | ||
| msg: "pre-commit is required: https://pre-commit.com/#install" | ||
| - sh: gitlance --not-on-remotes --head HEAD --help |
There was a problem hiding this comment.
Agreed, gitlance --help is enough. I'll simplify it.
Copying commit-msg and pre-push directly into .git/hooks can replace hooks that contributors already use. Configure both stages through pre-commit and install its dispatcher from the existing task. Pre-commit preserves prior hooks as legacy hooks, runs them alongside Gitlance, and keeps repeated installation idempotent. Reuse the commit-msg hook and the --not-on-remotes mode added by canonical#12 and canonical#13. Pre-commit passes the prepared message file to the existing hook. For pre-push, use a small adapter to select the pushed ref from PRE_COMMIT_TO_REF or PRE_COMMIT_LOCAL_BRANCH. This validates a branch that is not checked out and skips non-branch refs without changing the Gitlance CLI. Document the local setup and uninstall workflow. Closes: canonical#9 Signed-off-by: Dhruv Vaishnav <dhruvvaishav687@gmail.com>
266711e to
1e94c46
Compare
Closes #9
Summary
Copying
commit-msgandpre-pushdirectly into.git/hookscan replace hooks that contributors already use.This branch is based on #13, which includes the commit-message support from #12. The change on top is limited to pre-commit integration:
commit-msghook through pre-commit--not-on-remotesmodePRE_COMMIT_TO_REForPRE_COMMIT_LOCAL_BRANCHpre-commit installfromtask install-githooksThe Rust source changes displayed in the combined PR diff are inherited from #12 and #13. This contribution commit does not modify Gitlance's Rust code.
Testing
cargo fmt --all -- --checkcargo clippy --locked --all-targets --all-features -- -D warningscargo test --locked— 47 unit and 19 integration tests passedreuse lintcargo llvm-cov --locked report --fail-under-lines 70— 85.12% line coveragepre-commit validate-config .pre-commit-config.yamlpre-commit installcommit-msgand configuredpre-pushhook runs