pub struct GitModule { /* private fields */ }Expand description
Git module instance, tied to a Session.
Tracks which worktrees and branches were created by this session. Write operations check ownership before proceeding; read operations bypass the check entirely.
Implementations§
Source§impl GitModule
impl GitModule
Sourcepub async fn status(&self) -> Result<StatusOutput>
pub async fn status(&self) -> Result<StatusOutput>
Inspect the working tree and produce a StatusOutput split into
staged / unstaged / untracked buckets.
Runs the libgit2 work on the tokio::task::spawn_blocking pool.
Sourcepub async fn log(&self, filters: LogFilters) -> Result<LogOutput>
pub async fn log(&self, filters: LogFilters) -> Result<LogOutput>
Walk HEAD backwards, applying LogFilters and returning at most
filters.max_count matching commits.
Runs the libgit2 revwalk on the tokio::task::spawn_blocking pool.
Sourcepub async fn diff(&self, staged: bool) -> Result<DiffOutput>
pub async fn diff(&self, staged: bool) -> Result<DiffOutput>
Produce the patch for either the staged (HEAD vs index) or the
unstaged (index vs worktree) view, controlled by staged.
Runs the libgit2 diff on the tokio::task::spawn_blocking pool.
Sourcepub async fn worktree_list(&self) -> Result<WorktreeListOutput>
pub async fn worktree_list(&self) -> Result<WorktreeListOutput>
List every linked worktree, annotated with session-ownership.
Source§impl GitModule
impl GitModule
Sourcepub async fn fetch(
&self,
remote: Option<&str>,
refspec: Option<&str>,
prune: bool,
) -> Result<FetchOutput>
pub async fn fetch( &self, remote: Option<&str>, refspec: Option<&str>, prune: bool, ) -> Result<FetchOutput>
Fetch from a remote.
remote defaults to "origin". refspec is forwarded verbatim when
present. prune adds --prune so deleted upstream refs are removed
locally. The combined stdout + stderr is returned as raw for
transport diagnostics — successful fetches usually print nothing on
stdout but emit From <url> / <ref> -> <ref> lines on stderr.
Sourcepub async fn remote_list(&self) -> Result<RemoteListOutput>
pub async fn remote_list(&self) -> Result<RemoteListOutput>
Enumerate remotes with their fetch / push URLs.
We use git remote -v rather than git2’s Repository::remotes so the
output matches what git itself reports (and naturally handles the
case where fetch and push URLs diverge via pushurl).
Sourcepub async fn branch_status(
&self,
branch: &str,
base: &str,
) -> Result<BranchStatusOutput>
pub async fn branch_status( &self, branch: &str, base: &str, ) -> Result<BranchStatusOutput>
Compare branch against base and report ahead / behind counts plus
the merge-base, using git2’s graph_ahead_behind for the count and a
git merge-base shell-out for the common-ancestor sha (git2’s
merge_base returns an OID but we want the textual form).
Sourcepub async fn unpushed_commits(
&self,
branch: &str,
remote: &str,
) -> Result<UnpushedCommitsOutput>
pub async fn unpushed_commits( &self, branch: &str, remote: &str, ) -> Result<UnpushedCommitsOutput>
List commits that exist on branch but not on <remote>/<branch>.
Sourcepub async fn is_pushed(
&self,
commit: &str,
remote: &str,
) -> Result<IsPushedOutput>
pub async fn is_pushed( &self, commit: &str, remote: &str, ) -> Result<IsPushedOutput>
Check whether commit is reachable from any remote-tracking ref
under refs/remotes/<remote>/.
Sourcepub async fn tag_pushed(
&self,
tag: &str,
remote: &str,
) -> Result<TagPushedOutput>
pub async fn tag_pushed( &self, tag: &str, remote: &str, ) -> Result<TagPushedOutput>
Check whether tag exists on remote (via git ls-remote --tags).
Sourcepub async fn worktree_state(
&self,
branch: Option<&str>,
) -> Result<WorktreeStateOutput>
pub async fn worktree_state( &self, branch: Option<&str>, ) -> Result<WorktreeStateOutput>
Snapshot a worktree’s state (branch, tracking, ahead/behind, uncommitted).
Source§impl GitModule
impl GitModule
Sourcepub async fn reset(
&self,
working_dir: &Path,
mode: ResetMode,
target: &str,
force: bool,
) -> Result<ResetOutput>
pub async fn reset( &self, working_dir: &Path, mode: ResetMode, target: &str, force: bool, ) -> Result<ResetOutput>
Move HEAD to target, with mode controlling the working tree
behaviour. The working directory MUST be owned by the current
session — see GitModule::ensure_session_scope.
ResetMode::Soft— move HEAD only (git reset --soft)ResetMode::Mixed— also reset index but keep worktree (--mixed)ResetMode::Hard— also overwrite worktree (--hard)
force only affects Hard: without it, a hard reset is refused when
the repository has stash entries and the working tree is dirty —
the signature of “a stash was applied and is being cleaned up with the
biggest hammer available”, which is precisely how stashed work gets
destroyed. GitModule::stash_abort is the non-destructive undo;
force = true is for callers who mean the reset regardless.
Source§impl GitModule
impl GitModule
Sourcepub async fn session_release(&mut self) -> Result<SessionReleaseOutput>
pub async fn session_release(&mut self) -> Result<SessionReleaseOutput>
Adopt orphan worktrees under the session-scoped worktrees dir
(those known to git worktree list but not yet owned by this
session). Any branches currently checked out inside them are
adopted at the same time so the normal branch_delete ownership
check will pass. The worktrees dir is resolved by
[Session::worktrees_dir].
Returns the set of worktrees / branches that were newly adopted. Already-owned entries are skipped silently — calling this repeatedly is idempotent.
Source§impl GitModule
impl GitModule
Sourcepub async fn stash_list(&self) -> Result<StashListOutput>
pub async fn stash_list(&self) -> Result<StashListOutput>
List every stash entry, newest first.
Read-only, so no ownership check — the entries belong to the
repository, not to a session. Runs the libgit2 walk on the
tokio::task::spawn_blocking pool.
Sourcepub async fn stash_show(&self, index: usize) -> Result<StashShowOutput>
pub async fn stash_show(&self, index: usize) -> Result<StashShowOutput>
Show what stash@{index} would restore: the patch against the commit
the stash was taken on, plus the untracked paths it carries.
Read-only; nothing is applied. Runs the libgit2 diff on the
tokio::task::spawn_blocking pool.
Sourcepub async fn stash_apply(
&self,
working_dir: &Path,
index: usize,
expected_sha: Option<String>,
) -> Result<StashApplyOutput>
pub async fn stash_apply( &self, working_dir: &Path, index: usize, expected_sha: Option<String>, ) -> Result<StashApplyOutput>
Restore stash@{index} into working_dir without dropping it.
Preconditions, all of them refusals rather than best-effort merges:
expected_sha(when given) must match the entry atindex. The index shifts on every drop, the sha does not — pass it whenever the caller resolved the entry in an earlier turn.working_dirmust have no staged and no unstaged changes. Untracked files are fine. This is what makes the rollback below total: everything the working tree gains came from the stash, so undoing the apply can never eat a hand edit.- None of the entry’s untracked paths may already exist on disk — git would refuse halfway through and leave a partial apply.
On failure (conflict, or anything else git stash apply reports) the
working tree is rolled back automatically and the error says so. The
entry is never touched, so a failed apply costs nothing.
Sourcepub async fn stash_abort(
&self,
working_dir: &Path,
index: usize,
expected_sha: Option<String>,
) -> Result<StashAbortOutput>
pub async fn stash_abort( &self, working_dir: &Path, index: usize, expected_sha: Option<String>, ) -> Result<StashAbortOutput>
Undo an applied stash: every path stash@{index} touches goes back to
its HEAD state, and the entry itself is left alone.
This is a path-scoped revert, not a diff-aware one — edits made on top
of the applied stash are discarded together with it. That’s the
deliberate trade for GitModule::stash_apply’s clean-tree
precondition: within that contract, “back to HEAD” and “undo the
apply” are the same thing.
Sourcepub async fn stash_finalize(
&self,
working_dir: &Path,
index: usize,
expected_sha: Option<String>,
) -> Result<StashFinalizeOutput>
pub async fn stash_finalize( &self, working_dir: &Path, index: usize, expected_sha: Option<String>, ) -> Result<StashFinalizeOutput>
Drop stash@{index} once its content has been verified.
The sha is read before the drop and returned as
StashFinalizeOutput::dropped_sha: the stash commit stays reachable
until git gc prunes it, so GitModule::stash_restore can put the
entry back. Callers should record it — that record is the difference
between “dropped” and “lost”.
Sourcepub async fn stash_restore(
&self,
working_dir: &Path,
sha: &str,
message: Option<String>,
) -> Result<StashRestoreOutput>
pub async fn stash_restore( &self, working_dir: &Path, sha: &str, message: Option<String>, ) -> Result<StashRestoreOutput>
Put a dropped stash commit back on refs/stash.
sha is the StashFinalizeOutput::dropped_sha of an earlier
finalize (or any stash commit sha). Dropping only removes the reflog
entry — the commit itself lingers, unreferenced, until git gc prunes
it, and this call re-references it.
Guarded so refs/stash cannot be turned into a dumping ground:
shamust be >= 7 hex chars. Revspecs (HEAD, branch names,HEAD@{1}) are rejected — restoring is only ever about an object id somebody wrote down.- The object must resolve. When it doesn’t,
git gcis the likely reason and the error says so. - The commit must be stash-shaped (>= 2 parents). Storing an ordinary commit would produce an entry whose “apply” means something nobody intended.
- The entry must not already be in the list — a second reference to the same content is a footgun, not a restore.
message overrides the reflog message; when omitted the stash
commit’s own summary is reused, which is what the entry was called
before it was dropped.
Source§impl GitModule
impl GitModule
Sourcepub async fn worktree_add(
&mut self,
name: &str,
branch: &str,
base_branch: Option<&str>,
) -> Result<WorktreeAddOutput>
pub async fn worktree_add( &mut self, name: &str, branch: &str, base_branch: Option<&str>, ) -> Result<WorktreeAddOutput>
Create a new worktree at <worktrees_dir>/<name> on a new branch.
The worktrees dir is the session-scoped root returned by
[Session::worktrees_dir]; see [SessionConfig::worktrees_dir]
for the resolution precedence and setup expectation.
Sourcepub async fn worktree_remove(
&mut self,
name: &str,
) -> Result<WorktreeRemoveOutput>
pub async fn worktree_remove( &mut self, name: &str, ) -> Result<WorktreeRemoveOutput>
Remove a session-owned worktree (force-removed, then forgotten).
Sourcepub async fn commit(
&self,
working_dir: &Path,
message: &str,
only: Option<&[String]>,
other_staged: OtherStagedMode,
force_dot: bool,
) -> Result<CommitOutput>
pub async fn commit( &self, working_dir: &Path, message: &str, only: Option<&[String]>, other_staged: OtherStagedMode, force_dot: bool, ) -> Result<CommitOutput>
Stage and commit changes in working_dir.
only == None(or an empty slice): sweeps every change withgit add -Aand commits.other_stagedis ignored. Kept as the backward-compatible default so pre-existing callers see identical behaviour.only == Some(paths): commits exactlypaths. When the index already carries other staged work, the call is transactional underother_staged:Stop— return an error, leave the index untouched. Safe default, forces the caller to reconcile explicitly.Restage— unstage the intruding paths, stage + commitonly, then re-stage the intruders. The resulting commit contains exactlyonly; the pre-existing staged work stays in the index.
Untracked files listed in only are staged and committed like any
other path; anything not in only is never touched.
Dotfile / dot-dir safeguard. Any candidate whose path contains a
.-prefixed component (.env, .github/workflows/ci.yml,
foo/.hidden) is classified before staging:
- tracked → committed as usual, but recorded in
CommitOutput::dotfile_warningsso pre-publish review can catch unintended edits to.gitignore/ workflow files / etc. - untracked, not in
.gitignore→ dropped from staging + recorded in bothdotfile_warningsandCommitOutput::dotfile_skipped. - untracked, in
.gitignore→ silently skipped (matches git’s default;git status --porcelaindoesn’t surface them either). force_dot=true→ suppresses the entire mechanism: every candidate is staged verbatim and no warnings are emitted.
Sourcepub async fn merge(
&self,
branch: &str,
into_branch: &str,
working_dir: &Path,
) -> Result<MergeOutput>
pub async fn merge( &self, branch: &str, into_branch: &str, working_dir: &Path, ) -> Result<MergeOutput>
Merge branch into into_branch via --no-ff. On failure, the
merge is auto-aborted and the original error surfaces.
Sourcepub async fn branch_delete(&self, branch: &str) -> Result<BranchDeleteOutput>
pub async fn branch_delete(&self, branch: &str) -> Result<BranchDeleteOutput>
Delete a session-owned branch (refuses to delete unmerged work; use
git branch -D directly if you really need that).