Skip to content

feat: handle edge cases in commit-msg hook (GIT-85)#56

Merged
TonyCasey merged 2 commits intomainfrom
git-85
Feb 14, 2026
Merged

feat: handle edge cases in commit-msg hook (GIT-85)#56
TonyCasey merged 2 commits intomainfrom
git-85

Conversation

@TonyCasey
Copy link
Copy Markdown
Owner

@TonyCasey TonyCasey commented Feb 14, 2026

Summary

  • Skip analysis for merge commits (Merge branch/pull request/remote-tracking)
  • Skip analysis for fixup/squash/amend! commits (will be squashed later)
  • Skip analysis for revert commits (auto-generated)
  • Handle Unicode/emoji in commit messages gracefully
  • Handle very long commit messages (content truncated to 200 chars)

Changes

  • Added shouldSkipAnalysis() method to CommitMsgHandler
  • Updated shell hook to v4 with grep-based skip conditions
  • Added 13 new edge case tests

Test plan

  • Unit tests pass (419 tests)
  • Integration tests pass (91 tests)
  • New edge case tests cover all skip conditions

Closes GIT-85

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Improvements
    • Commit message analyzer now skips AI analysis for merge, fixup!, squash!, amend!, and revert commits.
    • Commit-msg hook bumped to v4 with enhanced early-exit checks for auto-generated or non-relevant commit messages.
  • Tests
    • Expanded and updated tests to verify skip behavior, trailer handling for regular commits/amendments, and edge cases (unicode, long messages, trailer truncation).

Skip analysis for special commit types:
- Merge commits (Merge branch/pull request/remote-tracking)
- Fixup/squash/amend! commits (will be squashed later)
- Revert commits (auto-generated)

Added shouldSkipAnalysis() to CommitMsgHandler with pattern detection.
Updated shell hook to v4 with grep-based skip conditions.

Also handles:
- Unicode/emoji in commit messages
- Very long commit messages (content truncated to 200 chars)
- Empty/whitespace-only messages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Decision: handle edge cases in commit-msg hook (GIT-85). Skip analysis for special commit types:
AI-Confidence: medium
AI-Tags: application, handlers, hooks, tests, integration, unit
AI-Lifecycle: project
AI-Memory-Id: 172b6832
Copilot AI review requested due to automatic review settings February 14, 2026 17:48
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

Adds pre-analysis skip logic for specific commit messages (merge, fixup/squash/amend, revert) implemented in the commit-msg hook and CommitMsgHandler; bumps hook fingerprint to v4 and updates unit and integration tests to expect skipped behavior for those commits.

Changes

Cohort / File(s) Summary
Handler Skip Logic
src/application/handlers/CommitMsgHandler.ts
Added private `shouldSkipAnalysis(message: string): string
Hook Script Updates
src/hooks/commit-msg.ts
Bumped commit-msg hook fingerprint from v3 to v4. Added shell-level early-exit guards to skip analysis for merge, fixup/squash/amend, and revert commits before JSON escaping and analyzer invocation.
Integration Tests
tests/integration/hooks/hook-commit-msg.test.ts
Replaced merge/PR-amend expectations with skip assertions (no AI-Agent trailers). Added tests for skipping fixup!, squash!, amend!, and Revert commits; retained tests for regular amend, unicode/emoji, and long-message truncation.
Unit Tests
tests/unit/hooks/commit-msg.test.ts
Updated expected hook fingerprint strings from git-mem:commit-msg v3 to git-mem:commit-msg v4 in three assertions.

Sequence Diagram(s)

sequenceDiagram
    participant Git as Git (client)
    participant Hook as commit-msg hook (shell)
    participant Handler as CommitMsgHandler (TS)
    participant Analyzer as AI Analyzer/Agent
    Git->>Hook: invoke with commit message
    Hook->>Hook: check fast-skip patterns (merge/fixup/squash/amend/revert/AI-Memory-Id)
    alt Hook decides to skip
        Hook-->>Git: exit successfully (no analysis)
    else continue
        Hook->>Handler: pass prepared JSON message
        Handler->>Handler: shouldSkipAnalysis(firstLine)
        alt Handler decides to skip
            Handler-->>Hook: return success (no trailers)
        else
            Handler->>Analyzer: autoAnalyze / inferTags / analysis
            Analyzer-->>Handler: analysis result (type/tags/decision)
            Handler->>Git: append trailers to commit-msg (if applicable)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main change: adding skip logic for edge cases (merge, fixup/squash/amend, revert commits) in the commit-msg hook.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch git-85

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/hooks/commit-msg.ts`:
- Around line 38-45: The shell commit-msg hook uses case-sensitive grep patterns
for merge/fixup/revert checks which can diverge from the TypeScript handler
CommitMsgHandler.shouldSkipAnalysis() that uses case-insensitive regex; make the
shell hook consistent by adding the -i flag to each grep -qE invocation for the
three checks (merge, fixup/squash, revert) so they perform case-insensitive
matching and align behavior with shouldSkipAnalysis(), or alternatively add a
brief comment above those grep lines explaining the intentional case-sensitive
choice.

In `@tests/unit/hooks/commit-msg.test.ts`:
- Line 105: Update the failing assertion message in the test that checks
content.includes('git-mem:commit-msg v4') so the human-readable message matches
the expected version; change the assertion message text from 'Should be upgraded
to v3' to 'Should be upgraded to v4' in the test containing
assert.ok(content.includes('git-mem:commit-msg v4')).

Comment thread src/hooks/commit-msg.ts Outdated
Comment thread tests/unit/hooks/commit-msg.test.ts Outdated
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the commit-msg hook’s robustness by skipping analysis (and trailer injection) for commit message types that are typically auto-generated or transient, and by hardening handling for Unicode and long commit messages.

Changes:

  • Added shouldSkipAnalysis() to CommitMsgHandler to bypass analysis for merge/fixup/squash/amend!/revert commit messages.
  • Updated the installed commit-msg shell hook fingerprint to v4 and added grep-based early-exit skip conditions.
  • Expanded integration coverage with additional edge-case scenarios (merge, fixup/squash/amend!, revert, unicode/emoji, long messages).

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/application/handlers/CommitMsgHandler.ts Adds centralized skip logic for special commit message types before analysis/trailer generation.
src/hooks/commit-msg.ts Bumps hook fingerprint to v4 and adds shell-level skip conditions to avoid invoking the Node handler.
tests/unit/hooks/commit-msg.test.ts Updates hook fingerprint expectations for install/wrap/upgrade tests.
tests/integration/hooks/hook-commit-msg.test.ts Adds/updates integration tests for skip cases and unicode/long-message handling.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/unit/hooks/commit-msg.test.ts Outdated
Comment thread src/hooks/commit-msg.ts Outdated
Comment thread tests/integration/hooks/hook-commit-msg.test.ts Outdated
- Add -i flag to grep for case-insensitive matching (matches TS handler)
- Fix assertion message: v3 → v4
- Fix truncation test: 250 → 200 chars (matches code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Gotcha: address PR review comments (GIT-85). - Add -i flag to grep for case-insensitive matching (matches TS handler)
AI-Confidence: medium
AI-Tags: hooks, tests, integration, unit
AI-Lifecycle: project
AI-Memory-Id: 9f67cb62
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@src/hooks/commit-msg.ts`:
- Around line 38-45: Read the commit message first line once into a variable
(e.g., first_line) and reuse it for the three checks instead of calling head -1
"$COMMIT_MSG_FILE" each time; then update the three guards that reference
COMMIT_MSG_FILE (the grep checks for "^Merge (branch|pull
request|remote-tracking)", "^(fixup|squash|amend)! ", and '^Revert "') to test
against the saved variable (first_line) and keep the same exit 0 behavior when a
match is found.

In `@tests/integration/hooks/hook-commit-msg.test.ts`:
- Around line 692-713: The test "should handle very long commit message"
currently only checks truncation if the decision trailer exists; update the
assertions to first assert that the AI-Decision trailer is present (e.g.,
assert.ok(decisionMatch, 'AI-Decision trailer must exist')) before asserting its
length, locating the relevant variables/expressions commitMsg, msgPath,
runHook('commit-msg', ...), modifiedMsg, and decisionMatch so that the test
fails if AI-Decision is missing and still enforces the 200-char truncation from
buildTrailers.

Comment thread src/hooks/commit-msg.ts
Comment on lines +38 to +45
# Skip merge commits (auto-generated by git)
head -1 "$COMMIT_MSG_FILE" | grep -qiE "^Merge (branch|pull request|remote-tracking)" && exit 0

# Skip fixup/squash commits (will be squashed later)
head -1 "$COMMIT_MSG_FILE" | grep -qiE "^(fixup|squash|amend)! " && exit 0

# Skip revert commits (auto-generated)
head -1 "$COMMIT_MSG_FILE" | grep -qiE '^Revert "' && exit 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Optional: avoid reading the first line three times.

You can capture the first line once and reuse it for the three skip checks to reduce subprocesses and keep the script a bit cleaner.

♻️ Optional refactor
-# Skip merge commits (auto-generated by git)
-head -1 "$COMMIT_MSG_FILE" | grep -qiE "^Merge (branch|pull request|remote-tracking)" && exit 0
-
-# Skip fixup/squash commits (will be squashed later)
-head -1 "$COMMIT_MSG_FILE" | grep -qiE "^(fixup|squash|amend)! " && exit 0
-
-# Skip revert commits (auto-generated)
-head -1 "$COMMIT_MSG_FILE" | grep -qiE '^Revert "' && exit 0
+# Skip merge commits (auto-generated by git)
+FIRST_LINE=$(head -n 1 "$COMMIT_MSG_FILE")
+printf '%s' "$FIRST_LINE" | grep -qiE "^Merge (branch|pull request|remote-tracking)" && exit 0
+
+# Skip fixup/squash commits (will be squashed later)
+printf '%s' "$FIRST_LINE" | grep -qiE "^(fixup|squash|amend)! " && exit 0
+
+# Skip revert commits (auto-generated)
+printf '%s' "$FIRST_LINE" | grep -qiE '^Revert "' && exit 0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Skip merge commits (auto-generated by git)
head -1 "$COMMIT_MSG_FILE" | grep -qiE "^Merge (branch|pull request|remote-tracking)" && exit 0
# Skip fixup/squash commits (will be squashed later)
head -1 "$COMMIT_MSG_FILE" | grep -qiE "^(fixup|squash|amend)! " && exit 0
# Skip revert commits (auto-generated)
head -1 "$COMMIT_MSG_FILE" | grep -qiE '^Revert "' && exit 0
# Skip merge commits (auto-generated by git)
FIRST_LINE=$(head -n 1 "$COMMIT_MSG_FILE")
printf '%s' "$FIRST_LINE" | grep -qiE "^Merge (branch|pull request|remote-tracking)" && exit 0
# Skip fixup/squash commits (will be squashed later)
printf '%s' "$FIRST_LINE" | grep -qiE "^(fixup|squash|amend)! " && exit 0
# Skip revert commits (auto-generated)
printf '%s' "$FIRST_LINE" | grep -qiE '^Revert "' && exit 0
🤖 Prompt for AI Agents
In `@src/hooks/commit-msg.ts` around lines 38 - 45, Read the commit message first
line once into a variable (e.g., first_line) and reuse it for the three checks
instead of calling head -1 "$COMMIT_MSG_FILE" each time; then update the three
guards that reference COMMIT_MSG_FILE (the grep checks for "^Merge (branch|pull
request|remote-tracking)", "^(fixup|squash|amend)! ", and '^Revert "') to test
against the saved variable (first_line) and keep the same exit 0 behavior when a
match is found.

Comment on lines +692 to +713
it('should handle very long commit message', () => {
process.env.GIT_MEM_AGENT = 'TestAgent/2.0';

// Create a long commit message (> 1000 chars)
const longBody = 'This is a detailed explanation. '.repeat(50);
const commitMsg = `feat: add comprehensive feature\n\n${longBody}\n\nBecause this decision will help with scaling.`;
const msgPath = createCommitMsgFile(repoDir, commitMsg);

const result = runHook('commit-msg', {
commit_msg_path: msgPath,
cwd: repoDir,
});

assert.equal(result.status, 0);

const modifiedMsg = readFileSync(msgPath, 'utf8');
assert.ok(modifiedMsg.includes('AI-Agent:'), 'Should handle long messages');
// Content should be truncated in trailers (200 char limit in buildTrailers)
const decisionMatch = modifiedMsg.match(/AI-Decision: (.+)/);
if (decisionMatch) {
assert.ok(decisionMatch[1].length <= 200, 'Trailer content should be truncated to 200 chars');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make the truncation test assert the decision trailer exists.

Right now the test passes even if AI-Decision is missing, so it won’t catch truncation regressions.

✅ Tighten the assertion
-      const decisionMatch = modifiedMsg.match(/AI-Decision: (.+)/);
-      if (decisionMatch) {
-        assert.ok(decisionMatch[1].length <= 200, 'Trailer content should be truncated to 200 chars');
-      }
+      const decisionMatch = modifiedMsg.match(/AI-Decision: (.+)/);
+      assert.ok(decisionMatch, 'Should include AI-Decision trailer');
+      assert.ok(decisionMatch[1].length <= 200, 'Trailer content should be truncated to 200 chars');
🤖 Prompt for AI Agents
In `@tests/integration/hooks/hook-commit-msg.test.ts` around lines 692 - 713, The
test "should handle very long commit message" currently only checks truncation
if the decision trailer exists; update the assertions to first assert that the
AI-Decision trailer is present (e.g., assert.ok(decisionMatch, 'AI-Decision
trailer must exist')) before asserting its length, locating the relevant
variables/expressions commitMsg, msgPath, runHook('commit-msg', ...),
modifiedMsg, and decisionMatch so that the test fails if AI-Decision is missing
and still enforces the 200-char truncation from buildTrailers.

@TonyCasey TonyCasey merged commit 1f0ce6b into main Feb 14, 2026
3 checks passed
@TonyCasey TonyCasey deleted the git-85 branch February 14, 2026 17:58
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.

2 participants