Skip to content

fix: hook improvements and init defaults (GIT-85)#55

Merged
TonyCasey merged 7 commits intomainfrom
git-85-hook-fixes
Feb 14, 2026
Merged

fix: hook improvements and init defaults (GIT-85)#55
TonyCasey merged 7 commits intomainfrom
git-85-hook-fixes

Conversation

@TonyCasey
Copy link
Copy Markdown
Owner

@TonyCasey TonyCasey commented Feb 14, 2026

Summary

  • Hooks install by default - git-mem init now installs all hooks automatically (no --hooks flag needed)
  • Fix hook chaining - commit-msg no longer skips when prepare-commit-msg runs first
  • No duplicate trailers - AI-Agent/AI-Model only added once even with both hooks

Changes

  1. Remove --hooks flag from init - hooks are core functionality
  2. Change commit-msg skip check from AI-Agent: to AI-Memory-Id:
  3. Skip adding Agent/Model in commit-msg if already present
  4. Bump commit-msg hook to v3

Test Plan

  • All 503 tests pass
  • Manual test: commit shows all trailers without duplicates
  • git-mem init -y installs all 3 hooks

Closes GIT-85

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Smart commit analysis: commit-msg hook auto-analyzes messages, detects memory types, infers tags, and adds AI trailers (configurable via .git-mem.json). Trailers now respect and preserve existing AI metadata.
  • Changes

    • Hook installation now always runs during init; init also configures pushing of git notes.
    • Git-mem hooks fingerprint bumped to v3; uninstall-hooks description updated.
  • Tests

    • Hook-related tests updated for new fingerprint and skip behavior.

Because users need to know about the new commit-msg hook feature that automatically adds AI trailers.

AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
Using the commit-msg hook because it automatically adds AI trailers.

AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
- Remove --hooks flag from init, hooks now install automatically
- Change commit-msg skip check from AI-Agent to AI-Memory-Id
- This allows prepare-commit-msg and commit-msg to work together
- Bump commit-msg hook to v3

Because both hooks need to run: prepare-commit-msg adds basic trailers,
commit-msg adds the full analysis (Decision/Gotcha/Convention, Tags, etc).

AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Decision: both hooks need to run: prepare-commit-msg adds basic trailers,
AI-Confidence: medium
AI-Tags: application, handlers, commands, hooks, tests, integration, unit, pattern:because-clause
AI-Lifecycle: project
AI-Memory-Id: d8ed5636
Skip adding AI-Agent and AI-Model in commit-msg if prepare-commit-msg
already added them. Both hooks now work together correctly.

AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Gotcha: prevent duplicate Agent/Model trailers. Skip adding AI-Agent and AI-Model in commit-msg if prepare-commit-msg
AI-Confidence: medium
AI-Tags: application, handlers, typescript
AI-Lifecycle: project
AI-Memory-Id: 70ce8b50
Copilot AI review requested due to automatic review settings February 14, 2026 15:11
@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

Detects completed analysis via AI-Memory-Id (not AI-Agent), threads existing commit message into trailer builders to avoid re-adding Agent/Model trailers, makes hook installation unconditional in init and adds configureNotesPush, bumps hook fingerprint to v3, and updates related tests and changelog.

Changes

Cohort / File(s) Summary
Changelog
CHANGELOG.md
Added Unreleased entry describing the new Smart commit analysis feature and .git-mem.json configuration.
Commit message handler
src/application/handlers/CommitMsgHandler.ts
Thread existingMessage through buildBasicTrailers and buildTrailers; change skip-detection to prefer AI-Memory-Id; make Agent/Model trailer addition conditional. (Method signatures updated to accept existingMessage.)
CLI / init command
src/cli.ts, src/commands/init.ts
Removed --hooks option, updated --uninstall-hooks description, removed hooks from IInitCommandOptions, made hook installation unconditional, added configureNotesPush(cwd: string) helper and call.
Hook script
src/hooks/commit-msg.ts
Bumped hook fingerprint from v2 → v3; skip logic now checks for AI-Memory-Id trailer to avoid re-analysis.
Tests
tests/integration/hooks/hook-commit-msg.test.ts, tests/unit/hooks/commit-msg.test.ts
Updated tests to expect AI-Memory-Id-based skip behavior and bumped hook fingerprint expectations to v3.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 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 'fix: hook improvements and init defaults' accurately describes the main changes: hook-related fixes (skip logic and duplicate prevention) and init command defaults (removing --hooks flag and adding note push configuration).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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-hook-fixes

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

git-mem init now configures remote.origin.push to include refs/notes/*
so notes travel with commits on regular git push.

AI-Agent: Claude-Code/2.1.42
AI-Model: claude-opus-4-5-20251101
AI-Decision: auto-configure git to push notes with commits. git-mem init now configures remote.origin.push to include refs/notes/*
AI-Confidence: medium
AI-Tags: commands, typescript
AI-Lifecycle: project
AI-Memory-Id: ff173fa7
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 updates git-mem’s init + hook behavior so hooks are installed by default, commit-msg no longer incorrectly short-circuits after prepare-commit-msg runs, and Agent/Model trailers aren’t duplicated when both hooks execute.

Changes:

  • Make git-mem init always install prepare-commit-msg, commit-msg, and post-commit hooks; remove the --hooks CLI flag.
  • Update commit-msg hook skip logic to key off AI-Memory-Id: and bump hook fingerprint to v3.
  • Prevent commit-msg from re-adding AI-Agent / AI-Model when already present (e.g., from prepare-commit-msg).

Reviewed changes

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

Show a summary per file
File Description
tests/unit/hooks/commit-msg.test.ts Updates expected commit-msg hook fingerprint to v3 in unit tests.
tests/integration/hooks/hook-commit-msg.test.ts Adjusts integration skip-condition test to use AI-Memory-Id instead of AI-Agent.
src/hooks/commit-msg.ts Bumps hook fingerprint to v3 and changes shell-level “skip if already analyzed” check to AI-Memory-Id.
src/commands/init.ts Removes hooks option and installs hooks unconditionally during init; uninstall removes all hooks.
src/cli.ts Removes --hooks flag from CLI; updates --uninstall-hooks description.
src/application/handlers/CommitMsgHandler.ts Changes “already analyzed” detection to AI-Memory-Id and skips adding Agent/Model if already present.
CHANGELOG.md Adds an Unreleased entry describing commit-msg “smart commit analysis”.

💡 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 CHANGELOG.md
Comment thread src/hooks/commit-msg.ts Outdated
Comment thread src/application/handlers/CommitMsgHandler.ts Outdated
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/commands/init.ts`:
- Around line 79-109: The configureNotesPush function overwrites existing
remote.origin.push entries when there is a single refspec; instead preserve
existing refspecs by reading all current entries (the existing variable from
execFileSync), splitting/counting them, and then: if no entries exist use
execFileSync with 'remote.origin.push' (no --add) to set the heads refspec, if
one or more entries exist do NOT call the non---add setter (avoid the
execFileSync that writes '+refs/heads/*:refs/heads/*' without --add), and always
add the notes refspec using the '--add' form only when 'refs/notes' is missing;
update the code paths around the two execFileSync calls so the heads setter is
conditional on existing count and the notes setter uses '--add' to avoid
clobbering user refspecs.

In `@tests/unit/hooks/commit-msg.test.ts`:
- Around line 104-106: The failure message for the first assertion is stale
("Should be upgraded to v1") while the test actually checks for
'git-mem:commit-msg v3'; update the assertion message passed to assert.ok (the
second argument) to reflect v3 (e.g., "Should be upgraded to v3") so the error
message matches the checked value; locate the assertion using
readFileSync(hookPath, 'utf8') and the assert.ok call that checks for
'git-mem:commit-msg v3'.

Comment thread src/commands/init.ts
Comment thread tests/unit/hooks/commit-msg.test.ts
- Fix assertion message: v1 → v3 in commit-msg.test.ts
- Clarify AI-Memory-Id comment wording in hook and handler
- Fix configureNotesPush to preserve existing user refspecs

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-73). - Fix assertion message: v1 → v3 in commit-msg.test.ts
AI-Confidence: medium
AI-Tags: application, handlers, commands, hooks, tests, unit
AI-Lifecycle: project
AI-Memory-Id: 605c296b
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: 1

🤖 Fix all issues with AI agents
In `@src/application/handlers/CommitMsgHandler.ts`:
- Around line 100-151: Both buildBasicTrailers and buildTrailers duplicate the
same Agent/Model presence check and resolution logic; extract a small helper
(e.g., addAgentAndModelTrailers or appendAgentModelIfMissing) that accepts the
existingMessage and the trailers array (or returns an array) and encapsulates
calls to this.agentResolver.resolveAgent(), this.agentResolver.resolveModel(),
and pushes { key: AI_TRAILER_KEYS.AGENT|MODEL, value } only when missing; then
replace the duplicated blocks in buildBasicTrailers and buildTrailers with calls
to that helper to keep logic DRY and avoid future divergence.

Comment on lines 100 to 151
/**
* Build basic AI-Agent and AI-Model trailers only (when autoAnalyze is false).
* Skips if already present from prepare-commit-msg.
*/
private buildBasicTrailers(): ITrailer[] {
private buildBasicTrailers(existingMessage: string): ITrailer[] {
const trailers: ITrailer[] = [];
const agent = this.agentResolver.resolveAgent();
const model = this.agentResolver.resolveModel();
const hasAgent = existingMessage.includes('AI-Agent:');
const hasModel = existingMessage.includes('AI-Model:');

if (agent) {
trailers.push({ key: AI_TRAILER_KEYS.AGENT, value: agent });
if (!hasAgent) {
const agent = this.agentResolver.resolveAgent();
if (agent) {
trailers.push({ key: AI_TRAILER_KEYS.AGENT, value: agent });
}
}
if (model) {
trailers.push({ key: AI_TRAILER_KEYS.MODEL, value: model });
if (!hasModel) {
const model = this.agentResolver.resolveModel();
if (model) {
trailers.push({ key: AI_TRAILER_KEYS.MODEL, value: model });
}
}

return trailers;
}

/**
* Build all AI-* trailers from the analysis result.
* Skips Agent/Model if they already exist (from prepare-commit-msg).
*/
private buildTrailers(
analysis: ReturnType<ICommitAnalyzer['analyze']>,
config: ICommitMsgConfig
config: ICommitMsgConfig,
existingMessage: string
): ITrailer[] {
const trailers: ITrailer[] = [];

// Always add Agent and Model via injected resolver
const agent = this.agentResolver.resolveAgent();
const model = this.agentResolver.resolveModel();
// Only add Agent and Model if not already present (prepare-commit-msg may have added them)
const hasAgent = existingMessage.includes('AI-Agent:');
const hasModel = existingMessage.includes('AI-Model:');

if (agent) {
trailers.push({ key: AI_TRAILER_KEYS.AGENT, value: agent });
if (!hasAgent) {
const agent = this.agentResolver.resolveAgent();
if (agent) {
trailers.push({ key: AI_TRAILER_KEYS.AGENT, value: agent });
}
}
if (model) {
trailers.push({ key: AI_TRAILER_KEYS.MODEL, value: model });
if (!hasModel) {
const model = this.agentResolver.resolveModel();
if (model) {
trailers.push({ key: AI_TRAILER_KEYS.MODEL, value: model });
}
}
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: dedupe Agent/Model trailer construction.

Both trailer builders reimplement the same Agent/Model logic; a small helper would prevent divergence.

♻️ Possible refactor
+  private buildAgentModelTrailers(existingMessage: string): ITrailer[] {
+    const trailers: ITrailer[] = [];
+    const hasAgent = existingMessage.includes('AI-Agent:');
+    const hasModel = existingMessage.includes('AI-Model:');
+
+    if (!hasAgent) {
+      const agent = this.agentResolver.resolveAgent();
+      if (agent) trailers.push({ key: AI_TRAILER_KEYS.AGENT, value: agent });
+    }
+    if (!hasModel) {
+      const model = this.agentResolver.resolveModel();
+      if (model) trailers.push({ key: AI_TRAILER_KEYS.MODEL, value: model });
+    }
+    return trailers;
+  }
+
   private buildBasicTrailers(existingMessage: string): ITrailer[] {
-    const trailers: ITrailer[] = [];
-    const hasAgent = existingMessage.includes('AI-Agent:');
-    const hasModel = existingMessage.includes('AI-Model:');
-    ...
-    return trailers;
+    return this.buildAgentModelTrailers(existingMessage);
   }
 
   private buildTrailers(..., existingMessage: string): ITrailer[] {
-    const trailers: ITrailer[] = [];
-    const hasAgent = existingMessage.includes('AI-Agent:');
-    const hasModel = existingMessage.includes('AI-Model:');
-    ...
-    return trailers;
+    const trailers: ITrailer[] = [
+      ...this.buildAgentModelTrailers(existingMessage),
+    ];
+    ...
+    return trailers;
   }
🤖 Prompt for AI Agents
In `@src/application/handlers/CommitMsgHandler.ts` around lines 100 - 151, Both
buildBasicTrailers and buildTrailers duplicate the same Agent/Model presence
check and resolution logic; extract a small helper (e.g.,
addAgentAndModelTrailers or appendAgentModelIfMissing) that accepts the
existingMessage and the trailers array (or returns an array) and encapsulates
calls to this.agentResolver.resolveAgent(), this.agentResolver.resolveModel(),
and pushes { key: AI_TRAILER_KEYS.AGENT|MODEL, value } only when missing; then
replace the duplicated blocks in buildBasicTrailers and buildTrailers with calls
to that helper to keep logic DRY and avoid future divergence.

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