safegit

command module
v0.17.2 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2026 License: MIT Imports: 29 Imported by: 0

README

safegit

Go CLI wrapper around git for safe concurrent multi-agent use.

The problem

When multiple AI agent sessions share a single git repository, they race on .git/index. Two agents staging files at the same time produce mixed commits -- files from one agent leak into another's commit, or writes are silently lost. Standard git has no built-in isolation for this scenario.

The solution

safegit wraps git plumbing commands behind a two-phase commit pipeline that keeps every invocation isolated. Per-invocation temporary index files prevent staging races. Ref updates use per-ref locks with compare-and-swap (CAS) retry, so concurrent commits to the same branch serialize correctly. An append-only operation log records every mutation. The output is standard git commits -- teammates, CI, and code review tools see nothing unusual.

Install

From source (requires Go 1.24+):

go install github.com/smm-h/safegit@latest

Pre-built binaries are available on GitHub Releases via goreleaser.

Quick start

cd your-repo
safegit commit -m "add feature X" -- src/foo.go src/bar.go
safegit push

safegit auto-initializes on first use (creates .git/safegit/). Use safegit doctor --uninstall to remove safegit from a repo.

Key commands

Command Description
commit Stage files and commit atomically (--amend to amend/reword)
undo Reverse the last commit/amend/reword via oplog
push Push with pre-pre-push hooks and retry logic
hook Manage pre-pre-push hooks (list, run, install)
doctor Health checks and repair (--fix to garbage-collect)
config Show or set configuration values
unlock Release a stale ref lock

Tree-mutating commands (checkout, pull, merge, rebase, reset, bisect, cherry-pick, revert) are passed through with coordination guards.

How it works

The commit pipeline has two phases. Phase A (parallel-safe) creates a temporary index, stages the requested files into it, and builds the tree object -- all without touching the shared .git/index. Phase B acquires a per-ref lock, reads the current tip, creates the commit with that parent, and updates the ref using CAS. If the ref moved between read and write, Phase B retries from the new tip (re-parenting the commit) with random jitter to avoid thundering-herd stampedes under heavy concurrency.

See docs/architecture.md for the full architecture specification.

Configuration

Run safegit config to view all settings, or safegit config <key> <value> to change one.

Key Default Description
commit.casMaxAttempts 5 Max CAS retry attempts for ref updates
lock.acquireTimeoutSeconds 30 Timeout waiting for a per-ref lock
hooks.preprepush.timeoutSeconds 1800 Timeout for pre-pre-push hook execution
push.retryAttempts 3 Number of push retry attempts
log.maxSizeMB 100 Max operation log size before rotation

Configuration is stored in .git/safegit/config.json. Remove the entire .git/safegit/ directory to return to vanilla git.

Known limitations

  • Same-machine concurrency only. Lock staleness detection uses PID liveness checks and hostname comparison. On network filesystems (NFS, CIFS), safegit doctor warns about reduced lock atomicity guarantees. Cross-machine lock reclaim is refused when the hostname doesn't match.
  • PID reuse. On Linux, safegit compares process start time against lock creation time via /proc to detect PID reuse. On other platforms, a reused PID could keep an orphan lock alive until the lock timeout expires. Use safegit unlock --force to clear a stuck lock.
  • Linux and macOS only. Windows is not supported (Unix-only syscalls for locking, signals, process management). WSL (Windows Subsystem for Linux) works since it runs the Linux binary natively.

License

MIT

Documentation

Overview

Package main is the entry point for the safegit CLI, a concurrency-safe git wrapper that isolates commits via per-invocation temporary indexes.

Directories

Path Synopsis
internal
commit
Amend and Reword implement tip-commit rewriting with CAS safety.
Amend and Reword implement tip-commit rewriting with CAS safety.
coord
Package coord implements the coordination layer that prevents concurrent agents from corrupting the working tree by guarding tree-mutating operations.
Package coord implements the coordination layer that prevents concurrent agents from corrupting the working tree by guarding tree-mutating operations.
git
Package git wraps os/exec calls to the git binary and is the sole interface through which safegit interacts with git plumbing commands.
Package git wraps os/exec calls to the git binary and is the sole interface through which safegit interacts with git plumbing commands.
hooks
Package hooks discovers and executes pre-pre-push hooks that run before any network I/O, solving the SSH timeout problem when checks are long-running.
Package hooks discovers and executes pre-pre-push hooks that run before any network I/O, solving the SSH timeout problem when checks are long-running.
index
Package index manages per-invocation temporary git indexes so each safegit invocation stages into its own index seeded from HEAD, avoiding contention.
Package index manages per-invocation temporary git indexes so each safegit invocation stages into its own index seeded from HEAD, avoiding contention.
lock
Package lock provides ref-lock primitives for concurrent ref updates using O_CREAT|O_EXCL for atomic lock file creation and exponential backoff polling.
Package lock provides ref-lock primitives for concurrent ref updates using O_CREAT|O_EXCL for atomic lock file creation and exponential backoff polling.
oplog
Package oplog implements the append-only JSONL operation log that records every mutating operation for undo support and audit trail purposes.
Package oplog implements the append-only JSONL operation log that records every mutating operation for undo support and audit trail purposes.
repo
Package repo manages the .git/safegit/ data directory including initialization, configuration loading, validation, and path helpers for all state files.
Package repo manages the .git/safegit/ data directory including initialization, configuration loading, validation, and path helpers for all state files.
scan
Package scan iterates all git objects (reachable and unreachable) and matches patterns against their textual content for history scrubbing.
Package scan iterates all git objects (reachable and unreachable) and matches patterns against their textual content for history scrubbing.
stage
Package stage implements hunk-level staging against temporary indexes by parsing unified diffs and applying selective patches for partial-file commits.
Package stage implements hunk-level staging against temporary indexes by parsing unified diffs and applying selective patches for partial-file commits.
submodule
Package submodule enumerates initialized and deinitialized git submodules, detects parent repos, checks for nesting, and resolves paths through symlinks.
Package submodule enumerates initialized and deinitialized git submodules, detects parent repos, checks for nesting, and resolves paths through symlinks.
testutil
Package testutil provides shared test helpers for creating temporary git repos, used across internal/*_test.go packages to avoid duplicating boilerplate.
Package testutil provides shared test helpers for creating temporary git repos, used across internal/*_test.go packages to avoid duplicating boilerplate.
trailer
Package trailer injects git trailers (key-value metadata lines) into commit messages for AI agent traceability and session attribution.
Package trailer injects git trailers (key-value metadata lines) into commit messages for AI agent traceability and session attribution.

Jump to

Keyboard shortcuts

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