Documentation
¶
Overview ¶
Package git exposes a minimal shell-out wrapper around the system `git` binary. The agent-memory project uses it for two reads:
- ActiveBranch resolves the current branch name (or short SHA, if HEAD is detached) for branch-aware local-state file resolution per design doc v0.4.1 §13.
- SlugBranch converts a branch name into the path-safe form used in local/current.<slug>.md filenames.
Writes (auto-stage, commit on apply) live in subsequent files in this package; M2 only ships the read path.
Index ¶
- Variables
- func AddPaths(root string, paths []string) ([]string, error)
- func ChangedFiles(root string) ([]string, error)
- func Checkout(ctx context.Context, dir, revision string) error
- func Clone(ctx context.Context, source, dest string) error
- func Commit(root, message string) (string, error)
- func HeadCommit(ctx context.Context, dir string) (string, error)
- func InstallMergeDriver(root string) error
- func IsWorkTree(dir string) bool
- func ListLocalBranches(root string) ([]string, error)
- func MergeDriverInstalled(root string) bool
- func SlugBranch(name string) string
- type BranchInfo
Constants ¶
This section is empty.
Variables ¶
var ErrGitNotInstalled = errors.New("git: executable not found on PATH")
ErrGitNotInstalled is returned by ActiveBranch when the `git` executable cannot be found on PATH.
Functions ¶
func AddPaths ¶
AddPaths runs `git add -- <paths...>` under root. Paths are repo-root- relative (forward or OS separator, git accepts both).
Semantics:
- root is not a git work tree → returns (nil, nil). Auto-stage on a non-git project is intentionally a no-op, not an error.
- git binary missing → returns ErrGitNotInstalled.
- Empty paths slice → returns (nil, nil).
- Real git failure (corrupt repo, locked index, etc.) → wrapped error.
The returned slice is the input paths verbatim on success; future extensions might filter to actually-staged paths via `--dry-run` first, but the v0.1 contract is "tell git to add these; trust git's behaviour".
Auto-stage NEVER calls `git add .` or any pattern broader than the explicit list. We stage only files our own pipeline just wrote.
func ChangedFiles ¶
ChangedFiles returns the repo-relative paths (forward-slash) of files with uncommitted changes in the working tree at root: modified, added, deleted, renamed, and untracked. It powers the "decisions/pitfalls referencing changed files" ranking signal (design §20.4) — sections that talk about a file you're currently touching should rank higher.
Behaviour mirrors ActiveBranch's "not a repo is not an error" contract:
- root not inside a git work tree → (nil, nil).
- `git` binary missing → ErrGitNotInstalled.
- any other git failure is wrapped and returned.
Paths are de-duplicated and returned in git's order. For renames (`R old -> new`) only the new path is reported. Deleted files are included (a decision may reference a file you just removed).
func Checkout ¶ added in v0.5.0
Checkout detaches HEAD at revision (a branch, tag, or commit SHA) in dir. Detaching means any ref kind is handled uniformly.
func Clone ¶ added in v0.5.0
Clone runs `git clone <source> <dest>`. source may be a remote URL or a local path (git clones local paths without a network); dest must not already exist. ctx cancellation kills a hung clone/fetch. No shallow flags — checking out an arbitrary pinned commit later needs full history, and landscape stores are small.
func Commit ¶
Commit creates a new commit with message under root and returns the commit SHA. Behaviour:
- root is not a git work tree → ("", nil). Symmetric with AddPaths.
- git binary missing → ErrGitNotInstalled.
- Nothing staged (`git diff --cached` is empty) → ("", nil). NOT an error — a no-op apply (idempotent re-apply with no on-disk change) should not produce empty commits.
- Real git failure (hook rejected, no user.email configured, etc.) → wrapped error including stderr.
Commit does NOT pass `--no-verify`. If the project has commit hooks, they run. Document for users: a slow pre-commit hook makes every apply slow; toggle `manifest.git.auto_commit: false` to opt out.
The message is passed verbatim to `git commit -m`. Multi-line messages (a title followed by a blank line and a body) are supported.
func HeadCommit ¶ added in v0.5.0
HeadCommit returns the full commit SHA at HEAD in dir.
func InstallMergeDriver ¶
InstallMergeDriver registers the section-aware merge driver in the repo's LOCAL git config (`.git/config`). This is per-clone state and cannot be committed, so each teammate runs it once after cloning; the matching `.gitattributes` entry (which IS committed) is written by the CLI.
Returns ErrGitNotInstalled if git is missing, or an error if root is not a git work tree.
func IsWorkTree ¶ added in v0.5.0
IsWorkTree reports whether dir is inside a git work tree. Used by sync to decide whether a local-path store can be pinned to a commit.
func ListLocalBranches ¶
ListLocalBranches returns every local branch name in the repo at root. Used by `memory.status` to detect orphan local files — `local/current.<slug>.md` whose slug doesn't correspond to any currently-existing branch.
Outside a git work tree returns (nil, nil) — symmetric with ActiveBranch's "not a repo is not an error" semantic.
func MergeDriverInstalled ¶
MergeDriverInstalled reports whether the merge driver is registered in the repo's local git config. Best-effort: any error (no git, not a repo) → false.
func SlugBranch ¶
SlugBranch converts a branch name to the path-safe slug used in local/current.<slug>.md filenames per design doc v0.4.1 §13.1.
Rules:
- lowercase
- alphanumeric (a-z, 0-9) survive
- any other rune (including '/', spaces, punctuation) becomes a dash
- runs of dashes collapse to a single dash
- leading/trailing dashes stripped
- empty input → empty output
Examples:
- "main" → "main"
- "feature/auth-rotation" → "feature-auth-rotation"
- "bugfix/JIRA-123" → "bugfix-jira-123"
- "release/2026.05.01" → "release-2026-05-01"
This is intentionally aggressive: branch names with unicode or odd punctuation collapse to a stable ASCII form that's safe on every filesystem we care about.
Types ¶
type BranchInfo ¶
type BranchInfo struct {
// Name is the symbolic branch name (e.g., "main", "feature/auth").
// Empty when IsDetached is true.
Name string
// ShortSHA is the abbreviated commit SHA, populated when IsDetached
// is true so callers can build a stable "current.detached-<sha>" file.
ShortSHA string
// IsDetached is true when HEAD does not point to a branch ref.
IsDetached bool
// IsGitRepo is false when the root is not inside any git working tree.
// In that case Name and ShortSHA are empty and no error is returned —
// the agent-memory layout falls back to a single shared local file.
IsGitRepo bool
}
BranchInfo describes the active branch of a repository.
func ActiveBranch ¶
func ActiveBranch(root string) (BranchInfo, error)
ActiveBranch resolves the branch info for the working tree at root.
Behaviour:
- root not a git repo → BranchInfo{IsGitRepo: false}, nil error.
- normal branch checked out → Name set, IsDetached false.
- detached HEAD → Name empty, ShortSHA set, IsDetached true.
- `git` binary missing → ErrGitNotInstalled.
All other git errors (e.g., corrupted .git, permission issues) are wrapped and returned.