Documentation
¶
Index ¶
- Variables
- func ExecPath(ctx context.Context) (string, error)
- type BranchRef
- type Client
- func (c *Client) AbortMerge(ctx context.Context) error
- func (c *Client) Authors(ctx context.Context) ([]string, error)
- func (c *Client) BranchExists(name string) (bool, error)
- func (c *Client) Checkout(ctx context.Context, branchName string) error
- func (c *Client) Commit(ctx context.Context, msg []byte, opts CommitOptions) error
- func (c *Client) CommitsAhead(ctx context.Context, branchName, baseBranch string) (int, error)
- func (c *Client) ConfigUser(ctx context.Context) (string, error)
- func (c *Client) CreateBranch(name, baseBranch string) error
- func (c *Client) CreateWorktree(ctx context.Context, branchName, baseBranch, path string) error
- func (c *Client) CurrentBranch() (string, error)
- func (c *Client) DefaultBaseBranch() (string, error)
- func (c *Client) DeleteLocalBranch(ctx context.Context, name string, force bool) error
- func (c *Client) DeleteLocalBranchSafe(ctx context.Context, branchName string, force bool, cfgBase string) error
- func (c *Client) DeleteRemoteBranch(ctx context.Context, branchName string) error
- func (c *Client) DeleteReviewRef(ctx context.Context, issueID string) error
- func (c *Client) FastForwardOnly(ctx context.Context, sourceBranch, targetBranch string) error
- func (c *Client) Fetch(ctx context.Context) error
- func (c *Client) FetchBranchRefs(ctx context.Context) error
- func (c *Client) FetchReviewRef(ctx context.Context, issueID string)
- func (c *Client) FetchReviewRefs(ctx context.Context) error
- func (c *Client) ForceDeleteBranch(name string) error
- func (c *Client) GitDir() (string, error)
- func (c *Client) IO() *pkg.IO
- func (c *Client) IsAncestor(ctx context.Context, child, ancestor string) (bool, error)
- func (c *Client) IsDirty(ctx context.Context) (bool, error)
- func (c *Client) IsMergedInto(branchName, baseBranch string) (bool, error)
- func (c *Client) ListReviewRefs(ctx context.Context) (map[string]*ReviewRef, error)
- func (c *Client) LocalBranchNames() ([]string, error)
- func (c *Client) MergeDryRun(ctx context.Context, branchName, baseBranch string) ([]string, error)
- func (c *Client) MergeForward(ctx context.Context, sourceBranch, targetBranch string) error
- func (c *Client) MergeNoFFNoCommit(ctx context.Context, featureBranch, baseBranch string) error
- func (c *Client) MergeRebase(ctx context.Context, featureBranch, baseBranch string) error
- func (c *Client) MergeSquash(ctx context.Context, branchName, baseBranch string) error
- func (c *Client) PushBranchRef(ctx context.Context, issueSlug string) error
- func (c *Client) PushReviewRef(ctx context.Context, issueID, expectedOldSHA string) error
- func (c *Client) ReadBranchRef(ctx context.Context, issueSlug string) (*BranchRef, error)
- func (c *Client) ReadReviewRef(ctx context.Context, issueID string) (*ReviewRef, string, error)
- func (c *Client) Remote() (string, error)
- func (c *Client) RemoteBranchExists(ctx context.Context, branchName string) bool
- func (c *Client) RepoName() (string, error)
- func (c *Client) ResetHard(ctx context.Context, target string) error
- func (c *Client) ResolveBranchRef(name string) (plumbing.Hash, error)
- func (c *Client) ResolveRef(name string) (plumbing.Hash, error)
- func (c *Client) RunGitAt(ctx context.Context, dir string, args ...string) error
- func (c *Client) SafeDeleteBranch(name string) error
- func (c *Client) SetRemote(name string)
- func (c *Client) WorkingTreeRoot() (string, error)
- func (c *Client) WriteBranchRef(ctx context.Context, issueSlug string, ref BranchRef) (string, error)
- func (c *Client) WriteReviewRef(ctx context.Context, issueID string, ref ReviewRef, oldSHA string) (string, error)
- type CommitOptions
- type ReviewRef
Constants ¶
This section is empty.
Variables ¶
var ErrBranchNotMerged = errors.New("git: branch not fully merged")
ErrBranchNotMerged is returned (wrapped) by SafeDeleteBranch / DeleteLocalBranch when git refuses to delete the branch because its tip commit is not fully merged into HEAD or upstream. Detect with errors.Is.
Functions ¶
Types ¶
type BranchRef ¶ added in v0.11.1
type BranchRef struct {
IssueSlug string `json:"issue_slug"`
BranchName string `json:"branch_name"`
ParentSlug string `json:"parent_slug,omitempty"`
CreatedAt string `json:"created_at"` // RFC3339
Merged bool `json:"merged,omitempty"`
// TrackerType records the tracker that created the issue ("" = manual). It
// is the cross-machine source of truth for whether an issue is tracker-born:
// stored in the git object (this blob) and fetched by every clone, so a
// reviewer with an empty local store can still tell whether to offer a
// tracker status update. omitempty keeps pre-existing refs backward-
// compatible — an absent field unmarshals to "" (treated as "manual").
TrackerType string `json:"tracker_type,omitempty"`
}
BranchRef is the JSON payload stored as a git blob at refs/zf/branches/<issueSlug>. It records the branch name and optional parent slug so any clone can resolve the merge target without querying the local SQLite store.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client wraps a go-git repository and exposes commit operations.
func NewClient ¶
NewClient opens the git repository that contains the current directory. ioStreams configures the streams used for interactive operations; nil uses os.Stdin/Stdout/Stderr.
func NewClientAt ¶ added in v0.4.2
NewClientAt opens the git repository rooted at dir. ioStreams configures the streams used for interactive operations; nil uses os.Stdin/Stdout/Stderr.
func (*Client) AbortMerge ¶ added in v0.9.3
AbortMerge runs `git merge --abort`. Used after a TUI abort or commit failure in the Classic close flow to clear MERGE_HEAD / MERGE_MSG and restore the working tree. Returns a wrapped error so callers can decide whether to treat a no-active-merge failure as fatal (e.g. by ignoring it when the orchestrator isn't sure whether MergeNoFFNoCommit actually started a merge).
func (*Client) Authors ¶
Authors returns a deduplicated list of commit author identities ("Name <email>") from the repository history, ordered by commit count (most active first). Uses `git shortlog -sne --all` so it walks every ref instead of just HEAD's ancestry, and tolerates partial packfiles that trip go-git's commit iterator (e.g. submodules with a malformed .idx). The current git config identity is prepended as the first (default) entry.
func (*Client) BranchExists ¶ added in v0.9.5
BranchExists returns true if refs/heads/<name> resolves locally. It does not consult remotes — see resolveBranchConflict for the rationale (no fetch on the happy path of `issue start`).
func (*Client) Checkout ¶ added in v0.8.0
Checkout switches the working tree to branchName. Wraps `git checkout <name>`. Idempotent: when the working tree is already on branchName, the call is a no-op — the underlying `git checkout` is skipped so heavyweight `post-checkout` hooks don't fire for a same-branch "switch". Returns a wrapped error from the git CLI on failure (e.g. unknown branch, untracked file collision).
func (*Client) Commit ¶
Commit records a commit with msg and the given options using the system git binary so that all configured hooks (pre-commit, commit-msg, post-commit) run.
func (*Client) CommitsAhead ¶ added in v0.11.0
CommitsAhead returns the number of commits in branchName that are not reachable from baseBranch. Uses `git rev-list --count <baseBranch>..<branchName>`.
func (*Client) ConfigUser ¶ added in v0.11.0
ConfigUser returns the git config user identity as "Name <email>". Returns an empty string when not configured.
func (*Client) CreateBranch ¶
CreateBranch creates a new branch from baseBranch and checks it out.
func (*Client) CreateWorktree ¶ added in v0.9.0
CreateWorktree creates a new branch from baseBranch and checks it out in a linked worktree at path. Wraps `git worktree add -b <branch> <path> <base>`.
func (*Client) CurrentBranch ¶ added in v0.4.2
CurrentBranch returns the short name of the branch HEAD points to. On a detached HEAD the returned name will not parse as an issue branch, so callers can simply ignore it.
func (*Client) DefaultBaseBranch ¶
DefaultBaseBranch resolves the default base branch in priority order:
- refs/remotes/<remote>/HEAD (skipped when no remote)
- "main" if the local ref exists
- "master" if the local ref exists
func (*Client) DeleteLocalBranch ¶ added in v0.4.2
DeleteLocalBranch deletes the local branch by name. force=true uses -D (required after squash merges); force=false uses -d (safe).
func (*Client) DeleteLocalBranchSafe ¶ added in v0.11.1
func (c *Client) DeleteLocalBranchSafe(ctx context.Context, branchName string, force bool, cfgBase string) error
DeleteLocalBranchSafe deletes branchName locally, switching to the configured base branch first when the current branch IS branchName (git refuses to delete the currently checked-out branch). cfgBase is used as the switch target; when empty the repo's default base branch (main/master) is auto-detected. On any checkout failure the function returns the error immediately.
func (*Client) DeleteRemoteBranch ¶ added in v0.11.0
DeleteRemoteBranch deletes branchName on the configured remote. No-op when no remote is configured.
func (*Client) DeleteReviewRef ¶ added in v0.11.0
DeleteReviewRef deletes refs/zf/reviews/<issueID> locally. If a remote is configured, also attempts to delete it there (best-effort; errors are ignored).
func (*Client) FastForwardOnly ¶ added in v0.8.0
FastForwardOnly checks out targetBranch and runs `git merge --ff-only sourceBranch`. Returns a wrapped error when the FF is refused (diverged history) so the caller can render an actionable message.
func (*Client) Fetch ¶ added in v0.9.0
Fetch runs `git fetch <remote>`. Returns nil immediately when no remote is configured (local-only repo). Returns a wrapped error when the remote is unreachable or auth fails.
func (*Client) FetchBranchRefs ¶ added in v0.11.1
FetchBranchRefs fetches refs/zf/branches/* from the remote into the local ref namespace. No-op when no remote is configured.
func (*Client) FetchReviewRef ¶ added in v0.11.1
FetchReviewRef fetches refs/zf/reviews/<issueID> from the remote into the local ref namespace. Silent — designed for use in pre-push hooks where interactive output would be confusing. No-op when no remote is configured. Errors are silently ignored (fail-open: the caller falls back to the local ref).
func (*Client) FetchReviewRefs ¶ added in v0.11.0
FetchReviewRefs fetches refs/zf/reviews/* from the remote into the local ref namespace. No-op when no remote is configured.
func (*Client) ForceDeleteBranch ¶ added in v0.10.0
ForceDeleteBranch invokes `git branch -D <name>` from the working tree root. Always destructive; safety check skipped.
func (*Client) GitDir ¶ added in v0.10.1
GitDir returns the absolute path of the repository's .git directory. For a regular repository this is "<worktree>/.git". For a submodule it is "<parent>/.git/modules/<name>" (because <worktree>/.git is a gitlink file, not a directory). For a linked worktree it is the per-worktree git dir. Resolved by shelling out to `git rev-parse --git-dir` to handle all forms.
func (*Client) IO ¶ added in v0.8.0
IO returns the injected IO streams. Callers should write status/diagnostic messages through these instead of os.Stdout/os.Stderr so Cobra-aware redirection (tests, subcommand piping, future TUI capture) keeps working.
func (*Client) IsAncestor ¶ added in v0.8.0
IsAncestor reports whether child is an ancestor of ancestor (or equal). Wraps `git merge-base --is-ancestor child ancestor`: exit code 0 → true, exit code 1 → false, any other exit code → wrapped error.
func (*Client) IsDirty ¶ added in v0.8.0
IsDirty reports whether the working tree has tracked-file modifications or staged-but-uncommitted changes. Wraps `git status --porcelain --untracked-files=no`. Untracked files are intentionally NOT counted as dirty: `git reset --hard` does not touch untracked content, so their presence does not put user work at risk during rollback.
func (*Client) IsMergedInto ¶
IsMergedInto reports whether branchName's tip commit is reachable from baseBranch, i.e. whether the branch has been merged into base (mirrors git merge-base --is-ancestor).
func (*Client) ListReviewRefs ¶ added in v0.11.0
ListReviewRefs returns all locally available review refs as a map of issueID → ReviewRef. Call FetchReviewRefs first to ensure the local namespace is up to date. Does not require the issue to exist in the store.
func (*Client) LocalBranchNames ¶
LocalBranchNames returns the short names of all local branches.
func (*Client) MergeDryRun ¶ added in v0.4.2
MergeDryRun checks whether branchName merges cleanly into baseBranch. It uses `git merge-tree --write-tree` (git 2.38+) to perform a 3-way merge in-memory: the working tree is never touched, no hooks run, and submodules are not traversed. Returns the list of conflicting file paths, or nil if clean.
func (*Client) MergeForward ¶ added in v0.11.0
MergeForward checks out targetBranch and runs `git merge --no-edit sourceBranch`, creating a merge commit. Used by `review sync` to integrate a parent integration branch into a drifted sub-task branch without rewriting history (no force-push needed). Returns a wrapped error on conflict; the caller should run AbortMerge to clean up.
func (*Client) MergeNoFFNoCommit ¶ added in v0.9.3
MergeNoFFNoCommit checks out baseBranch and runs `git merge --no-ff --no-commit <featureBranch>`. Leaves MERGE_HEAD + MERGE_MSG in place so the caller can drive the commit step itself (typically via the commitizen TUI form). Caller is responsible for `git merge --abort` on TUI abort or commit failure.
func (*Client) MergeRebase ¶ added in v0.8.0
MergeRebase prepares featureBranch for a single-commit close. When a remote is configured, it merges against remote/<baseBranch> and soft-resets to the same ref. When no remote is available (local-only repo), it uses the local baseBranch directly.
The mechanic is a real `git merge --no-edit <remoteBase>` (submodule-safe — handles gitlinks correctly, unlike `merge --squash`) followed by `git reset --soft <remoteBase>`, leaving HEAD at <remoteBase>, the working tree at the merged state, and the index staged with the consolidated diff. The transient merge commit produced by the merge step is unreachable after the reset and is eventually garbage-collected — `--no-edit` is what prevents git from opening $EDITOR for that throwaway commit message.
Caller is responsible for the final commit (typically via the commitizen TUI form) and for rollback on failure.
func (*Client) MergeSquash ¶ added in v0.4.2
MergeSquash checks out baseBranch and squash-merges branchName into it, leaving the squashed changes staged. The caller is responsible for the follow-up commit (so it can drive an interactive commit form).
func (*Client) PushBranchRef ¶ added in v0.11.1
PushBranchRef pushes refs/zf/branches/<issueSlug> to the remote. No-op when no remote is configured. Uses --force because the ref points to a blob (not a commit) and git rejects non-force updates of blob refs; it is also needed when stamping Merged:true on an existing ref after close.
func (*Client) PushReviewRef ¶ added in v0.11.0
PushReviewRef pushes refs/zf/reviews/<issueID> to the remote using --force-with-lease to prevent overwriting a concurrently updated ref. Pass expectedOldSHA="" to allow any prior value (first push). No-op when no remote is configured.
func (*Client) ReadBranchRef ¶ added in v0.11.1
ReadBranchRef reads the BranchRef for issueSlug from the local ref store. Returns (nil, nil) when the ref does not exist.
func (*Client) ReadReviewRef ¶ added in v0.11.0
ReadReviewRef reads the ReviewRef for issueID from the local ref store. Returns (nil, "", nil) when the ref does not exist. The returned currentSHA is suitable as oldSHA in the next WriteReviewRef call.
func (*Client) Remote ¶ added in v0.9.0
Remote returns the resolved remote name, auto-detecting on first call.
Resolution order:
- Already pinned via SetRemote → return as-is.
- Exactly one remote → cache and return its name.
- Zero remotes → return ("", nil); caller treats this as local-only.
- Multiple remotes, one named "origin" → use "origin" (git convention).
- Multiple remotes, none named "origin" → error with actionable message.
func (*Client) RemoteBranchExists ¶ added in v0.11.1
RemoteBranchExists reports whether branchName exists on the configured remote. Uses git ls-remote so no fetch is required. Returns false on any error or when no remote is configured.
func (*Client) RepoName ¶ added in v0.9.0
RepoName returns a short identifier for this repository. Resolution order:
- Last path segment of the configured remote URL, with ".git" stripped.
- Base name of the working tree root directory (local-only fallback).
func (*Client) ResetHard ¶ added in v0.8.0
ResetHard runs `git reset --hard <target>`. Used by the close orchestrator to atomically roll the current branch back to its original tip on TUI abort or commit failure. Does not touch untracked files.
func (*Client) ResolveBranchRef ¶ added in v0.11.1
ResolveBranchRef resolves a branch short name to its commit hash. It tries refs/heads/<name> first, then falls back to refs/remotes/<remote>/<name> so that sub-task closes work when the parent integration branch was never checked out locally (exists only as a remote tracking ref).
func (*Client) ResolveRef ¶ added in v0.8.0
ResolveRef returns the commit hash that `name` resolves to (with reference indirection followed). Use it for read-only ref lookups from packages that need a plumbing.Hash without taking a dependency on go-git's plumbing API.
func (*Client) RunGitAt ¶ added in v0.11.0
RunGitAt runs an arbitrary git command in dir with the client's IO streams. Exported for review subcommands that need low-level git operations.
func (*Client) SafeDeleteBranch ¶ added in v0.10.0
SafeDeleteBranch invokes `git branch -d <name>` from the working tree root. On git's "not fully merged" refusal the returned error wraps ErrBranchNotMerged.
func (*Client) SetRemote ¶ added in v0.9.0
SetRemote pins the remote name used for all remote operations. Call this when the user has configured branch.remote explicitly.
func (*Client) WorkingTreeRoot ¶
WorkingTreeRoot returns the absolute path of the repository's working tree root.
func (*Client) WriteBranchRef ¶ added in v0.11.1
func (c *Client) WriteBranchRef(ctx context.Context, issueSlug string, ref BranchRef) (string, error)
WriteBranchRef writes a BranchRef as a git blob and updates the local ref refs/zf/branches/<issueSlug>. No CAS — branch metadata is write-once; an overwrite (e.g. re-running issue start) simply replaces the blob. Returns the new blob SHA.
func (*Client) WriteReviewRef ¶ added in v0.11.0
func (c *Client) WriteReviewRef(ctx context.Context, issueID string, ref ReviewRef, oldSHA string) (string, error)
WriteReviewRef atomically writes a ReviewRef as a git blob and updates the local ref refs/zf/reviews/<issueID> using CAS. oldSHA must be the current ref SHA — pass "" for the first write (no prior value). Returns the new SHA.
type CommitOptions ¶
type CommitOptions struct {
All bool
Amend bool
NoVerify bool
Signoff bool
AllowEmpty bool
Author string // "Name <email>"; empty = git config identity
}
CommitOptions configures Client.Commit.
type ReviewRef ¶ added in v0.11.0
type ReviewRef struct {
Status string `json:"status"`
Round int `json:"round"`
FeatureSHA string `json:"feature_sha"`
Reviewer string `json:"reviewer,omitempty"`
CreatedAt string `json:"created_at"` // RFC3339
}
ReviewRef is the JSON payload stored as a git blob at refs/zf/reviews/<IssueID>.