Skip to main content

Module reflog

Module reflog 

Source
Expand description

mkit reflog [<ref>] — read-only view over the persisted ref-history journal (issue #231).

§What the journal actually records

mkit’s ref-history is the per-branch, append-only commit-history MMR (mkit_core::history::CommitHistory, the refs-history.lock journal written by write_ref_recording_history). It records one leaf per branch ref WRITE, not one leaf per commit that ends up reachable from the tip. For most operations — a plain commit, branch creation, merge, cherry-pick, amend, a rebase --abort rollback, fetch/pull tip update — each new commit corresponds to exactly one ref write, so “one leaf per advance” and “one leaf per commit” coincide in practice.

rebase is the documented exception (issue #648): a multi-commit rebase detaches HEAD for the whole operation and moves it once per replayed commit (refs::write_head_detached, NOT write_ref_recording_history), then performs exactly ONE branch ref write at finalize. A rebase that replays five commits therefore appends exactly one leaf, not five — the intermediate replayed commits are perfectly valid, reachable, mkit-created commits that were simply never in scope for per-commit journaling. The same gap applies to any future op that moves detached HEAD through multiple commits before a single branch-ref finalize. The journal therefore stores:

  • the count of recorded ref writes (len()), and
  • a tamper-evident root plus per-leaf inclusion proofs.

It deliberately does not store what a Git reflog stores: there is no op label, no old→new pair, no per-entry timestamp or message, and — crucially — the leaf digests are BLAKE3 values with the leaf position mixed in, so the original commit hashes cannot be read back out of the MMR. The MMR can only confirm a hash you already hold (via verify_inclusion).

§What mkit reflog therefore surfaces

Because the readable hashes can only come from the object store, not the MMR, reflog walks the branch tip’s first-parent chain (newest → oldest) — the same reconstruction history::rebuild_from_chain uses — and presents it as the branch’s movement history, addressed <branch>@{N} with @{0} = current tip. On a build with --features history-mmr it additionally cross-checks each commit against the journaled MMR root: it asks the journal to confirm, via an inclusion proof, that the commit was recorded as a branch advance at some leaf position. The recorded-advance count is reported in the summary line. The check is rewrite-robust — a reachable commit shows [journaled] as long as it was journaled at some point, even after a later amend/reset shifted the journal’s leaf count past the reachable chain length.

A reachable commit that does not verify is printed as [not journaled], deliberately worded to describe absence rather than imply tampering: per the rebase gap above, an intermediate rebase-replayed commit is expected to show this marker every time — it is a normal consequence of one-leaf-per-ref-write, not evidence of anything wrong with the commit or the journal. A [not journaled] marker on a commit that was NOT created by a mid-rebase replay (e.g. a plain commit, or a rebase’s own finalize tip) is the more interesting case worth investigating.

This is not a full Git reflog: @{N} indexes the reachable first-parent chain (which drops superseded commits — e.g. after an --amend or a reset the old tip is no longer listed), not the raw append log of every movement. See the help text / man mkit for the exact contract.

Read-only: this command never mutates refs, the journal, or any object.

Functions§

run