Skip to main content

Module plan

Module plan 

Source
Expand description

The plan: what is in the working tree, how it divides into commits, and the fingerprint that says the plan is still about this tree.

§Why a plan is a value with a fingerprint on it

A plan is derived from a working tree at a moment. In a repository worked by one person at a time that is a detail; in this one it is the correctness question. Several workers share a checkout, more share a repository, and a plan computed at one HEAD and executed at another commits files somebody else staged, under a message about work that is no longer what changed.

PlanFingerprint is what makes that detectable rather than merely unlikely: the repository, the worktree, HEAD, and the exact set of paths and states the plan was derived from. A plan carries it, and anything that acts on a plan compares it with the tree in front of it first. The comparison is cheap, it is not a lock, and it does not prevent the race — it refuses to be the one that loses it silently.

§What grouping is and is not

Grouping is a recommendation with its reasoning attached, never an automatic split. The evidence is what the repository can see: which directories changed, which scope the history gives them, and which files are derived from which. Where that evidence supports one commit it says one; where it supports several it says several and says why; where it supports nothing it says so, which is the honest answer for a tree of unrelated edits that only a person can divide.

use majordomus_cli::commit::{ChangeStage, PlanFingerprint, WorkingTreeState};
use majordomus_cli::commit::plan::PathChange;

let change = |path: &str, stage| PathChange {
    path: path.into(), stage, status: "M.".into(), partial: false,
};
let tree = WorkingTreeState {
    head: Some("a1b2c3d4e5f60718293a4b5c6d7e8f9012345678".into()),
    changes: vec![change("src/a.rs", ChangeStage::Staged)],
    ..WorkingTreeState::default()
};

// The same tree fingerprints the same way every time.
let made = PlanFingerprint::of("/repo/.git", "/repo", &tree);
assert!(made.differs_from(&PlanFingerprint::of("/repo/.git", "/repo", &tree)).is_none());

// Another worktree of the same repository is a different subject, and is named as one.
let elsewhere = PlanFingerprint::of("/repo/.git", "/repo-wt/feature/x", &tree);
let why = made.differs_from(&elsewhere).expect("another worktree");
assert!(why.contains("another worktree"), "{why}");

Structs§

CommitGroup
One commit a plan proposes. One commit a plan proposes: its message, its paths, and why those paths are one commit.
CommitPlan
A plan over a working tree.
PathChange
One path, and where it stands.
PlanFingerprint
What a plan was derived from.
WorkingTreeState
What git says about the working tree right now.

Enums§

ChangeStage
Where one path stands between the index and the working tree.

Functions§

derived_among
Which of paths this repository declares derived, asked of git rather than parsed.
group
Group a set of paths into the commits the evidence supports.
kind_of
The kind a set of paths suggests, from what the paths are.
messages_in
Every commit in range, as a subject and a body, newest first.
working_tree
Read git status --porcelain=v2 --branch, which reports the branch, the upstream and the divergence in the same call as the paths.