Documentation
¶
Overview ¶
Package git provides helpers for interacting with git repositories, focused on worktree and branch management for Clank's session isolation.
All functions shell out to the git CLI rather than using a Go git library. This keeps the dependency footprint small and ensures exact behavioral parity with the user's installed git version.
Index ¶
- Variables
- func AbortMerge(dir string) error
- func AddAll(dir string) error
- func AddWorktree(repoDir, worktreeDir, branch string) error
- func AddWorktreeNewBranch(repoDir, worktreeDir, branch, base string) error
- func AheadBehind(dir, local, remote string) (ahead, behind int, err error)
- func BackupRef(dir, name, target string) error
- func BranchExists(dir, branch string) (bool, error)
- func Checkout(dir, branch string) error
- func CloneBare(ctx context.Context, url, gitDir, token, branch, credentialHelper string) error
- func CloneShallowKeepRemote(ctx context.Context, url, dir, token, branch string) error
- func Commit(dir, message string) error
- func CommitLog(dir, base, branch string) (string, error)
- func CommitsAhead(dir, base, branch string) (int, error)
- func CommonDir(dir string) (string, error)
- func ConflictedFiles(dir string) ([]string, error)
- func CurrentBranch(dir string) (string, error)
- func DefaultBranch(dir string) (string, error)
- func DeleteBranch(dir, branch string, force bool) error
- func DiffStat(worktreeDir, base string) (added, removed int, err error)
- func Fetch(dir, remote, ref string, opts PushOptions) error
- func FetchBundleObjects(dir, bundlePath string) error
- func GetLocalConfig(dir, key string) (string, error)
- func HasStagedChanges(dir string) (bool, error)
- func HeadBranch(dir string) (string, error)
- func HeadCommit(dir string) (string, error)
- func Init(ctx context.Context, dir, defaultBranch string) error
- func InitBare(ctx context.Context, gitDir, defaultBranch string) error
- func IsAncestor(dir, ancestor, descendant string) (bool, error)
- func IsClean(dir string) (bool, error)
- func IsMerging(dir string) bool
- func IsRemoteNotConfigured(err error) bool
- func LocalBranches(dir string) ([]string, error)
- func LsRemoteDefaultBranch(ctx context.Context, url string) (string, error)
- func MainWorktreeRoot(dir string) (string, error)
- func Merge(dir, ref, message string) error
- func MergeBase(dir, ref1, ref2 string) (string, error)
- func MergeFF(dir, ref string) error
- func MergeNoFF(dir, branch, message string) error
- func PruneWorktrees(dir string) error
- func Push(dir, remote, refspec string, opts PushOptions) error
- func RemoteAdd(dir, name, url string) error
- func RemoteTrackingBranchExists(dir, remote, branch string) (bool, error)
- func RemoteURL(dir, remote string) (string, error)
- func RemoteURLs(dir string) (map[string]string, error)
- func RemoveWorktree(repoDir, worktreeDir string, force bool) error
- func RepoRoot(dir string) (string, error)
- func ResetHard(dir, ref string) error
- func RevParse(dir, ref string) (string, error)
- func SetLocalConfig(dir, key, value string) error
- func WorkingTreeDirty(dir string) (bool, error)
- func WorktreeDir(projectName, branch string) (string, error)
- type BranchTip
- type PushOptions
- type Worktree
Constants ¶
This section is empty.
Variables ¶
var ( // ErrPushNotFastForward fires when the remote branch has commits // the local branch doesn't. Callers should surface a 409 with a // "rebase or force-push" hint; v1 doesn't auto-force. ErrPushNotFastForward = errors.New("git push: not a fast-forward") // ErrPushRepoNotFound fires when the remote URL is reachable but // the repo isn't (404 from GitHub). GitHub deliberately returns // "Repository not found" for both 404 and 403 (private repos // without access) so an attacker can't enumerate. ErrPushRepoNotFound = errors.New("git push: repository not found or no access") // ErrPushPermissionDenied fires for explicit auth failures (e.g. // 401 from the remote). Distinct from ErrPushRepoNotFound — this // one means "we found the repo but our token can't write". ErrPushPermissionDenied = errors.New("git push: permission denied") )
Push errors that callers map to specific HTTP statuses or UI messages. Anything else surfaces via the wrapping error from Push.
var ErrMergeConflict = errors.New("git merge: conflicts")
ErrMergeConflict is returned by Merge when the merge stops on conflicts. The repository is left mid-merge (MERGE_HEAD present) so the caller can inspect ConflictedFiles, hand resolution to an agent, or AbortMerge.
var ErrNothingToCommit = fmt.Errorf("nothing to commit")
ErrNothingToCommit is returned by Commit when there are no staged changes.
Functions ¶
func AddAll ¶
AddAll stages all changes (tracked and untracked) in the working tree at dir. Equivalent to `git add -A`.
func AddWorktree ¶
AddWorktree creates a new worktree for an existing branch.
func AddWorktreeNewBranch ¶
AddWorktreeNewBranch creates a new worktree with a new branch based on the given base ref.
func AheadBehind ¶
AheadBehind returns how many commits local has that remote lacks (ahead) and how many remote has that local lacks (behind), via `git rev-list --left-right --count local...remote`. Both revisions must resolve in dir's object store; an unknown revision returns an error (callers treat that as "remote advanced past a commit we don't have").
func BackupRef ¶
BackupRef points the fully-qualified ref name at target (typically HEAD before a destructive reset), keeping discarded work recoverable. name must be fully qualified, e.g. "refs/clank/backup/<branch>-<sha>".
func BranchExists ¶
BranchExists returns true if the given branch exists locally.
func CloneShallowKeepRemote ¶
CloneShallowKeepRemote shallow-clones url into dir (--depth 1) keeping the .git directory and the origin remote — for importing a user's existing repo, where history depth doesn't matter but the link back to the remote does. token authenticates HTTPS clones of private repos; pass "" for public repos. branch checks out a specific branch (empty clones the remote's default). dir must not already exist.
The token reaches git through cloneTokenEnv + an inline credential helper rather than the URL, so it appears neither in argv nor in the resulting .git/config. The leading empty credential.helper resets any system/global helper so it can't shadow ours.
func Commit ¶
Commit creates a commit in the repository at dir with the given message. Returns ErrNothingToCommit if the working tree is clean (nothing staged).
func CommitLog ¶
CommitLog returns a one-line-per-commit log of commits on branch that are not on base. Format: "<short-hash> <subject>". Newest first.
func CommitsAhead ¶
CommitsAhead returns the number of commits that branch has ahead of base. For example, CommitsAhead(dir, "main", "feat/login") returns how many commits feat/login has that main does not.
func CommonDir ¶
CommonDir returns the repo's shared git directory (absolute): a non-bare repo's `.git`, a linked worktree's parent repo git dir, or a bare repo's own path. The primitive under MainWorktreeRoot, exposed for callers that want the git dir itself (e.g. resolving which canonical a linked worktree belongs to).
func ConflictedFiles ¶
ConflictedFiles returns the working-tree paths with unresolved merge conflicts (the "U" entries of `git diff --diff-filter=U`). Empty when there are none.
func CurrentBranch ¶
CurrentBranch returns the currently checked-out branch in dir. Returns "HEAD" if in detached HEAD state.
func DefaultBranch ¶
DefaultBranch returns the default branch name for the repository containing dir. It checks for refs/heads/main first, then refs/heads/master, then falls back to whatever HEAD points to on origin, and finally returns "main" as a last resort.
func DeleteBranch ¶
DeleteBranch deletes a local branch. If force is true, uses -D (force delete) instead of -d (safe delete, requires branch to be fully merged).
func DiffStat ¶
DiffStat returns the total lines added and removed in a worktree compared to the given base branch. This includes both staged and unstaged changes. The base is typically the repo's default branch (e.g. "main").
func Fetch ¶
func Fetch(dir, remote, ref string, opts PushOptions) error
Fetch refreshes one ref from the named remote, using the same process-local auth pattern as Push. Used by callers that need origin/<base> to exist before running a local diff against it (e.g. host.Service.CreatePR's commits-ahead check on a sprite whose worktree was migrated piecemeal without main ever being fetched).
Errors are returned verbatim; callers decide whether a fetch failure is fatal. A common pattern is to log + continue, since the downstream check has its own fallback.
func FetchBundleObjects ¶
FetchBundleObjects loads the git objects from the bundle file at bundlePath into the repo at dir's object store, without moving any branch or touching the working tree. Afterwards, commits contained in the bundle (e.g. a remote HEAD) are available for ancestry checks before any destructive apply.
func GetLocalConfig ¶
GetLocalConfig reads a repository-local git config value from the repo at dir. Returns ("", nil) when the key is unset — the read-side counterpart of SetLocalConfig.
func HasStagedChanges ¶
HasStagedChanges returns true if there are staged changes ready to commit. This checks the index against HEAD, ignoring unstaged and untracked files.
func HeadBranch ¶
HeadBranch returns the branch HEAD symbolically points at in the repo at dir. This is the canonical's default branch — DefaultBranch's main/master probing is wrong for single-branch clones of a repo whose default is neither. Errors on a detached HEAD.
func HeadCommit ¶
HeadCommit returns the full SHA of HEAD in dir.
func Init ¶
Init initializes a new git repository at dir with defaultBranch as the initial branch (git init -b <branch>). dir is created if needed.
func InitBare ¶
InitBare creates an empty bare repository at gitDir with HEAD pointing at defaultBranch — the greenfield canonical, which gets its first commit via a filesystem push from the scaffold's temp checkout.
func IsAncestor ¶
IsAncestor reports whether commit `ancestor` is an ancestor of `descendant` (i.e. descendant is reachable from ancestor) in the repo at dir. Both commits must already be present in the local object store. Used to gate a fast-forward pull.
func IsClean ¶
IsClean returns true if the working tree at dir has no uncommitted changes (no staged, unstaged, or untracked files). Used to verify the main worktree is safe to merge into.
func IsMerging ¶
IsMerging returns true if the repository at dir is in the middle of a merge (i.e., MERGE_HEAD exists). This is useful to detect conflicts after a failed merge.
func IsRemoteNotConfigured ¶
IsRemoteNotConfigured reports whether err came from RemoteURL finding no such remote configured (git config --get exits 1), as opposed to a real git/filesystem failure (corrupt config, missing repo, etc.) that happens to occur on the same call — those must not be treated as "no remote".
func LocalBranches ¶
LocalBranches returns the list of local branch names in the repository containing dir.
func LsRemoteDefaultBranch ¶
LsRemoteDefaultBranch asks a remote for the branch its HEAD points at, deliberately without credentials: `-c credential.helper=` resets any configured helpers and GIT_TERMINAL_PROMPT=0 fails fast instead of prompting, so a successful answer proves the URL is publicly clonable. Unlike GitHub's REST API, anonymous git smart-HTTP is not subject to the tiny unauthenticated per-IP rate limit.
func MainWorktreeRoot ¶
MainWorktreeRoot returns the top-level directory of the *main* worktree for the repo containing dir. Inside a `git worktree add`-ed worktree, RepoRoot returns the worktree's own path; this helper follows the shared `.git` to find the parent repo. Used when we need to derive a stable "project root" for naming purposes (e.g. the `~/.clank/worktrees/<project>/<branch>/` convention).
func Merge ¶
Merge merges ref into the current branch — fast-forwarding when possible, otherwise creating a merge commit with message. Returns ErrMergeConflict when the merge stops on conflicts; the repo is left mid-merge for the caller to resolve (ConflictedFiles) or AbortMerge.
func MergeBase ¶
MergeBase returns the best common ancestor of ref1 and ref2, or an empty string when none exists (git exits 1). A real error is only returned for unexpected failures. Used as a safety check before pushing to a remote: an empty result means our branch has no shared history with the remote's base, which almost always means the remote points at the wrong repo.
func MergeFF ¶
MergeFF fast-forwards the current branch to ref. Fails rather than creating a merge commit when the branch can't be fast-forwarded (local has commits ref lacks). Gate with IsAncestor(HEAD, ref) first.
func MergeNoFF ¶
MergeNoFF merges the given branch into the current branch using --no-ff (always creates a merge commit). The message is the commit message for the merge commit. Returns nil on success, an error if conflicts occur or the merge fails for another reason.
func PruneWorktrees ¶
PruneWorktrees runs `git worktree prune` in the repo at dir, dropping bookkeeping for worktree dirs that no longer exist on disk (manual rm, failed adds).
func Push ¶
func Push(dir, remote, refspec string, opts PushOptions) error
Push runs `git push` against the configured remote with the given refspec. Returns one of the typed errors above when the failure is classifiable, otherwise wraps git's stderr.
The auth header is passed via process-internal git config (-c http.extraheader=...) so it never persists to disk. It does land in `ps` output for the duration of the subprocess; we accept that — the sprite is single-user and the token is base64-encoded inside the header value.
func RemoteAdd ¶
RemoteAdd runs `git remote add <name> <url>` in dir — used when publishing a previously remote-less worktree to a fresh GitHub repo. Errors if the remote already exists.
func RemoteTrackingBranchExists ¶
RemoteTrackingBranchExists reports whether refs/remotes/<remote>/<branch> resolves in dir. (BranchExists checks refs/heads only.) Used to guard ahead/behind computations that need a tracking ref to compare against.
func RemoteURL ¶
RemoteURL returns the URL of the named remote (typically "origin") for the repository containing dir. Returns an error when the remote is not configured — callers must decide whether to treat that as fatal or degrade gracefully (a brand-new local repo may have no remotes yet).
func RemoteURLs ¶
RemoteURLs returns every configured remote's URL, keyed by remote name. Used by the host's CreateSession when a caller passes Dir: any remote whose canonical form matches the requested GitRef counts as a valid match (people fork-then-add-upstream all the time).
func RemoveWorktree ¶
RemoveWorktree removes a worktree. If force is true, uses --force to remove even if the worktree has uncommitted changes.
func ResetHard ¶
ResetHard moves the current branch and working tree to ref, discarding local commits and uncommitted changes not reachable from ref. Destructive — callers should BackupRef the prior HEAD first when the discarded work might be wanted back.
func RevParse ¶
RevParse resolves ref (a branch, tag, or revision expression such as FETCH_HEAD) to a full commit SHA in dir.
func SetLocalConfig ¶
SetLocalConfig sets a repository-local git config value (git config <key> <value>) in the repo at dir. Used to give a freshly-initialised project a committer identity so the initial commit doesn't depend on global git config being present on the host.
func WorkingTreeDirty ¶
WorkingTreeDirty reports whether the working tree at dir has any uncommitted changes, INCLUDING untracked (but not gitignored) files. Use this for surfacing "you have local work" to the user; for "is it safe to fast-forward" use IsClean, which ignores untracked files git preserves across a merge.
func WorktreeDir ¶
WorktreeDir returns the conventional Clank worktree directory path for a branch. Convention: ~/.clank/worktrees/<project-name>/<sanitized-branch>/
Types ¶
type BranchTip ¶
BranchTip is one refs/heads entry: the branch, its tip SHA, and the tip commit's committer time.
func LocalBranchTips ¶
LocalBranchTips returns every refs/heads/* tip via a single for-each-ref invocation — the repo overview's git half without N× `git log`. Ordered most recently committed first.
type PushOptions ¶
type PushOptions struct {
// ExtraHeader is appended to every HTTP request git makes during
// this push. Empty value means no header is sent (the default).
ExtraHeader string
}
PushOptions controls how Push invokes git. ExtraHeader, when set, is passed via `-c http.extraheader=<value>` so the credential never lands in `.git/config`, the remote URL, or `ps` output. Callers build the header value (typically "Authorization: Basic <b64(x-access-token:tok)>") themselves — this package stays agnostic to credential format.
type Worktree ¶
type Worktree struct {
Path string // Absolute filesystem path of the worktree
Branch string // Branch checked out in this worktree (short name, e.g. "main")
Bare bool // True if this is the bare repository entry
Head string // HEAD commit hash
}
Worktree represents a git worktree entry as returned by `git worktree list --porcelain`.
func FindWorktreeForBranch ¶
FindWorktreeForBranch returns the worktree that has the given branch checked out, or nil if no worktree exists for that branch.
func ListWorktrees ¶
ListWorktrees returns all worktrees for the repository containing dir.