feat: validate only commits not yet on any remote - #13
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>
There was a problem hiding this comment.
Pull request overview
This PR updates gitlance’s local-hook workflow to avoid re-validating already-published commits by validating only commits not yet reachable from any remote-tracking ref, and adds a commit-msg hook path via --message-file validation (addressing Issue #10’s root-commit validation gap).
Changes:
- Add
--not-on-remotesmode to validate commits reachable from--headbut not from any remote-tracking ref, with a clean success when there’s nothing new to check. - Add
--message-filemode to validate a single commit message file (forcommit-msghook usage), including git-like comment/scissors stripping. - Update hooks/tasks/tests/docs to support the new CLI behavior.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/integration_tests.rs | Refactors test runner to capture process output; adds integration coverage for --not-on-remotes and --message-file. |
| Taskfile.yml | Installs the new commit-msg hook alongside pre-push. |
| src/main.rs | Adds new CLI flags and routes execution into message-file, not-on-remotes, or base/head range modes. |
| src/lib.rs | Re-exports new git helpers used by the CLI. |
| src/git.rs | Adds remote-tracking ref enumeration, commit selection via exclude sets, and commit-message parsing utilities + unit tests. |
| README.md | Documents direct CLI usage, including --message-file and --not-on-remotes. |
| githooks/pre-push | Switches new-branch behavior to --not-on-remotes while keeping existing-branch merge-base behavior. |
| githooks/commit-msg | New hook that validates the commit message file via --message-file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
jw-can
left a comment
There was a problem hiding this comment.
LGTM, nice and clean!
My only comment for potential future work: There's diverging code paths depending on arguments of the same command. Could the strategy design pattern help with organizing this?
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 and runs them alongside Gitlance, while repeated installation remains idempotent. Reuse the message-file and not-on-remotes support from canonical#12 and canonical#13. Existing pushes use PRE_COMMIT_FROM_REF and PRE_COMMIT_TO_REF as an exact range, complete-history pushes fall back to unpublished-commit validation, and non-branch refs are skipped. Add focused integration coverage for each pre-push path and document the local setup and uninstall workflow. Closes: canonical#9 Signed-off-by: dhruvxvaishnav <dhruvvaishnav687@gmail.com>
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 --message-file and --not-on-remotes modes added by canonical#12 and canonical#13. The commit-msg stage passes the prepared message file, while the pre-push stage validates commits reachable from HEAD that are not present on a remote. Document the local setup and uninstall workflow. Closes: canonical#9 Signed-off-by: Dhruv Vaishnav <dhruvvaishav687@gmail.com>
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 --message-file and --not-on-remotes modes added by canonical#12 and canonical#13. The commit-msg stage passes the prepared message file. 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>
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>
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: #10