Help us shape the future of Go! Take the 2026 Go Developer Survey

gitmeta

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 9, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package gitmeta is the stdlib-only, best-effort git introspection layer that detects when a resolved CodeGraph index belongs to a different git working tree than the caller (WORK-01/02/03). It shells out to the local `git` binary via os/exec — no pure-Go git library, no CGo (D-03/D-04) — and is deliberately free of internal/query and internal/mcp concerns, so Phase 5's git sync hooks can reuse it unchanged.

Every function here degrades to a safe zero value on ANY failure: missing git, a non-repo path, a timeout, or a transient error all report "no signal" rather than an error. A read query must never fail or block on git being unavailable, slow, or absent (WORK-03).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CommonDir

func CommonDir(ctx context.Context, dir string) string

CommonDir returns the absolute, symlink-resolved git COMMON directory for dir — the shared `.git` every worktree of one repository points at, or "" when dir isn't a repo. Linked worktrees of the SAME repository report the SAME common dir; a submodule or an embedded clone is a DIFFERENT repository and reports its own (e.g. `.git/modules/<name>`, or its own `.git`). That distinction is what separates a genuine borrowed worktree from a nested repo the parent index already covers (see DetectIndexMismatch gate 4).

func HooksDir

func HooksDir(ctx context.Context, projectRoot string) string

HooksDir returns the git hooks directory for projectRoot, resolved via `git rev-parse --git-path hooks` — the only correct way to honor core.hooksPath and linked worktrees (which share the main checkout's common hooks dir). A relative result is joined against projectRoot; an absolute result (the case for linked worktrees) is passed through unchanged. Unlike CommonDir, this deliberately does NOT call realpath: D-04 specifies resolve-or-passthrough only, not symlink resolution. Degrades to "" on any error, empty output, or non-repo projectRoot.

func IsGitRepo

func IsGitRepo(ctx context.Context, dir string) bool

IsGitRepo reports whether dir is inside a git working tree. It follows the same exec contract as WorktreeRoot/CommonDir (gitTimeout, cmd.Dir, cmd.Stdin nil) and degrades to false on any failure — missing git, a non-repo path, a timeout, or a transient error all report "no signal" rather than propagating an error (D-10, ported from TS sync/git-hooks.js isGitRepo).

func WorktreeRoot

func WorktreeRoot(ctx context.Context, dir string) string

WorktreeRoot returns the absolute, symlink-resolved toplevel of the git working tree that dir belongs to, or "" when dir isn't inside a git repo (or git is unavailable/slow). `git rev-parse --show-toplevel` reports the PER-WORKTREE root: the main checkout and each linked worktree resolve to their own distinct directory — exactly the distinction detection needs.

Types

type CachingDetector

type CachingDetector struct {
	// contains filtered or unexported fields
}

CachingDetector memoizes DetectIndexMismatch verdicts — POSITIVE and NEGATIVE — keyed on TS's own cache key (startPath + "\x00" + indexRoot, per D-13). Detection costs up to four git subprocesses (see DetectIndexMismatch's doc comment); on a long-lived MCP server that would otherwise re-pay that cost on every single tool call.

The cache deliberately lives HERE, not on internal/query.Engine: internal/mcp's openEngine builds a FRESH Engine on every single tool call by design, so an Engine-scoped cache would yield zero cross-call benefit on the exact long-lived surface the cache exists for. internal/mcp constructs one CachingDetector per server and closes over it in every handler; the CLI constructs one per invocation (free — it's one-shot); both surfaces share this identical type (D-13, corrected 2026-07-15).

func NewCachingDetector

func NewCachingDetector() *CachingDetector

NewCachingDetector returns a ready-to-use, empty CachingDetector.

func (*CachingDetector) Detect

func (d *CachingDetector) Detect(ctx context.Context, startPath, indexRoot string) *Mismatch

Detect returns the memoized DetectIndexMismatch verdict for (startPath, indexRoot), computing and caching it on first call. Negative verdicts (nil == "checked, no mismatch") are cached too — a bare nil lookup can't distinguish "not yet checked" from "checked, none found", so presence is tracked via the two-value map form, never a nil test (D-13).

Detect is safe to call on a nil *CachingDetector: it falls through directly to DetectIndexMismatch, uncached, so every consumer can treat the detector as optional.

BL-01: a verdict computed under a CANCELLED ctx is never written to the cache, even though it IS returned for this call (WORK-03: never block or error a read on a failed/aborted git probe). A cancelled git spawn collapses into the same nil DetectIndexMismatch returns for "checked, no mismatch" — caching it would let one cancelled call permanently poison this (startPath, indexRoot) entry for a long-lived server's entire remaining life. See the ctx.Err() check below for the mechanism.

WR-02: a startPath that is not an existing, statable directory can never be inside a working tree — DetectIndexMismatch's gate 1 (WorktreeRoot) would immediately return "" for it anyway, so this is a pure short-circuit, not a behavior change. Rejecting it BEFORE the cache lookup/store means a client that mints a fresh nonexistent "path" on every call (accidentally, via a stale reference, or a malicious/looping MCP client) cannot grow the cache at all, on top of the maxCacheEntries bound below for legitimate, existing paths.

type Mismatch

type Mismatch struct {
	WorktreeRoot string `json:"worktreeRoot"`
	IndexRoot    string `json:"indexRoot"`
}

Mismatch describes a detected "borrowed index" situation: startPath lives in one git working tree, but the resolved CodeGraph index belongs to a different one. The json tags match TS's `--json` object shape (`{worktreeRoot, indexRoot}`) so plan 02-04 can embed this directly into StatusResult.

func DetectIndexMismatch

func DetectIndexMismatch(ctx context.Context, startPath, indexRoot string) *Mismatch

DetectIndexMismatch detects when startPath lives in one git working tree but the resolved CodeGraph index (indexRoot) belongs to a DIFFERENT working tree — the silent "worktree queries the main branch's graph" correctness bug (WORK-01). Ported verbatim from TS sync/worktree.js's detectWorktreeIndexMismatch (D-02), gate order and polarity preserved exactly.

Worst case this spawns four git subprocesses (two WorktreeRoot, two CommonDir) — gates 1-3 each short-circuit before reaching CommonDir, so most calls spawn one or two. This per-call cost is what motivates CachingDetector (Task 3): a long-lived MCP server must not re-pay it on every tool call.

Returns nil ("nothing to warn about") — never an error, never a panic — on every degradation path, including git being absent, slow, or the path not being a git repo at all (WORK-03).

func (*Mismatch) Notice

func (m *Mismatch) Notice() string

Notice renders the compact, single-line form of a detected mismatch, prefixed onto the other seven read tools' output (D-12). Returns "" on a nil receiver. Ported verbatim from TS sync/worktree.js's worktreeMismatchNotice (D-01/D-11); do not paraphrase.

func (*Mismatch) Warning

func (m *Mismatch) Warning() string

Warning renders the verbose, multi-line form of a detected mismatch, used by `status` only (D-12). Returns "" on a nil receiver so callers never need a nil guard — the same shape internal/query/render_markdown.go's staleBanner uses. Ported verbatim from TS sync/worktree.js's worktreeMismatchWarning (D-01/D-11); do not paraphrase, including the quoted "codegraph init -i" advice.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL