From b80ec8e30b940adf0b25b154d262bc8662836b25 Mon Sep 17 00:00:00 2001 From: tae2089 Date: Sat, 11 Jul 2026 09:36:13 +0900 Subject: [PATCH] Use incremental update in the pre-commit hook MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pre-commit hook ran "ccg build ." — a full re-parse of the entire repo on every commit. A commit only changes a few files, so use "ccg update ." which re-parses just the changed files (hash-based) and preserves existing graph state. Verified with the real binary that update builds correctly from an empty graph (first commit) and skips unchanged files on subsequent runs. Co-Authored-By: Claude Fable 5 --- internal/cli/hooks.go | 6 ++++-- internal/cli/hooks_test.go | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/internal/cli/hooks.go b/internal/cli/hooks.go index 782b048..1b2677e 100644 --- a/internal/cli/hooks.go +++ b/internal/cli/hooks.go @@ -21,7 +21,9 @@ func buildHookBody(strict bool) string { if strict { lint = "ccg lint --strict" } - return "\n" + hookGuardBegin + "\nccg build . && ccg docs && " + lint + "\n" + hookGuardEnd + "\n" + // Use the incremental update on commit: it re-parses only the changed files (fast) and + // preserves graph state, whereas a full build re-parses the whole repo every commit. + return "\n" + hookGuardBegin + "\nccg update . && ccg docs && " + lint + "\n" + hookGuardEnd + "\n" } // newHooksCmd creates the top-level hooks command group. @@ -49,7 +51,7 @@ func newHooksInstallCmd() *cobra.Command { cmd := &cobra.Command{ Use: "install", Short: "Install ccg pre-commit git hook", - Long: `Install a pre-commit hook that runs "ccg build && ccg docs && ccg lint". + Long: `Install a pre-commit hook that runs "ccg update && ccg docs && ccg lint". Use --strict to block commits when lint finds issues. If a pre-commit hook already exists, the ccg block is appended (idempotent).`, diff --git a/internal/cli/hooks_test.go b/internal/cli/hooks_test.go index d026855..a1e30d2 100644 --- a/internal/cli/hooks_test.go +++ b/internal/cli/hooks_test.go @@ -25,7 +25,7 @@ func TestHooksInstall_CreatesPreCommitHook(t *testing.T) { } hook := string(content) - for _, want := range []string{"#!/bin/sh", "ccg build", "ccg docs", "ccg lint"} { + for _, want := range []string{"#!/bin/sh", "ccg update", "ccg docs", "ccg lint"} { if !strings.Contains(hook, want) { t.Errorf("expected %q in hook, got:\n%s", want, hook) } @@ -106,8 +106,8 @@ func TestHooksInstall_ExistingHook_AppendsWithGuard(t *testing.T) { if !strings.Contains(hook, "existing hook") { t.Errorf("expected original hook content to be preserved") } - if !strings.Contains(hook, "ccg build") { - t.Errorf("expected ccg build to be appended") + if !strings.Contains(hook, "ccg update") { + t.Errorf("expected ccg update to be appended") } } @@ -134,9 +134,9 @@ func TestHooksInstall_Idempotent(t *testing.T) { // Should not have duplicate ccg blocks hook := string(content) - first := strings.Index(hook, "ccg build") - last := strings.LastIndex(hook, "ccg build") + first := strings.Index(hook, "ccg update") + last := strings.LastIndex(hook, "ccg update") if first != last { - t.Errorf("ccg build appears multiple times in hook (not idempotent):\n%s", hook) + t.Errorf("ccg update appears multiple times in hook (not idempotent):\n%s", hook) } }