Skip to main content

Module shadow

Module shadow 

Source
Expand description

The shadow repository and the replay of captured changes onto it. What: The shadow repository and the replay of captured changes onto it. Why: Commit preparation works on a shadow, so its helpers stay together.

In TS you’d write (pseudocode):

// shadow/index.ts: one `export * from './file'` per module below.

Modules§

empty_tree
The empty tree’s object name under each known object format. What: The object name of the empty tree under each object format Git supports, known without asking Git. Why: The invocation capture needs the empty tree as the baseline of an unborn branch. Git hashes the framed bytes tree 0 followed by a NUL byte, so the name depends on the object format alone and never on the repository’s contents. Spawning git hash-object -t tree --stdin for a constant cost a process on every commit.
replay_capture_order
Replay: capture order over the landed first-parent history and the per-path decision (replay_capture_order). What: The capture-order decision for one shared path of a replay. Why: When the prepared commit and every landed commit that changed a path captured it from the same worktree, the later capture’s bytes land, which is what sequential native commits record from the shared disk. Every other path keeps subsumption and then the three-way merge. The service decides it from the capture stamps it keeps (service_captures.rs); this is the answer’s shape.
replay_containment
Replay: the one-sided extension of subsumption over zero-context hunks (replay_containment). What: The context-tolerant half of replay’s subsumption: whether each prepared change is the landed change extended by the prepared commit’s own edit on one side. Why: Strict reverse application rejects a prepared file holding the landed edit plus an own edit next to it, because that own edit sits in the landed hunk’s context. Reading both changes as zero-context hunks in base coordinates accepts exactly the one-sided extensions and still rejects own edits on both sides and modify/delete conflicts.
replay_merge
Replay: the merge tree, the first conflicting landed commit, and the replayed commit rebuild (replay_merge). What: The merge step of one replay: the tree from git merge-tree --write-tree of the prepared change onto the landed tip. Why: A commit that lost the race to another is prepared again over the tip the service names; the merge says whether the two changes meet cleanly and, when they do not, which paths conflict, in byte order.
replay_patch
Replay: the unified-diff parser of subsumption (replay_patch). What: The unified-diff parser that replay’s subsumption reads: git diff-tree -p output over single-level trees named by decimal index, split into hunks per entry name. Why: Subsumption decides from hunk lines and their markers; the parser keeps every byte exact, so a hunk line round-trips to the blob bytes it came from.
replay_reverse_apply
Replay: the exact strict reverse check of subsumption (replay_reverse_apply). What: The exact emulation of git apply --reverse --check for one text file: the subsumption test that asks whether a landed change already sits in the prepared bytes. Why: Git’s apply.c matching (apply_one_fragment, find_pos, match_fragment) with its defaults: no context reduction, no whitespace fixing, no overlapping hunks, and anchoring at the file’s start and end. Replay must give the same answer as Git for the same bytes.
replay_shadow
Replay: the shadow-repository Git runner that every replay step uses (replay_shadow). What: Running real Git against the shadow repository for replay: the shadow selection, an optional private index, bytes on standard input, and the caller’s kept global options when a signed rebuild needs them. Why: Every replay step runs in git --git-dir=<shadow> so its objects stay in the shadow store until the next migration; one runner keeps the selection in one place.
replay_shared_paths
Replay: shared paths of the landed history and the prepared commit, with their three entries (replay_shared_paths). What: The paths both the prepared commit and the landed history changed since the preparation base, with the three tree entries subsumption compares. Why: Subsumption decides per shared path; the listing is two git diff-tree runs whatever the history length, and paths stay Latin-1 decoded so every byte survives and encodes back exactly.
replay_subsumption
Replay: subsumption rules and the synthetic merge base (replay_subsumption). What: Subsumption before replay’s three-way merge: the per-path rules, and the synthetic merge base that makes git merge-tree take the prepared bytes for every subsumed path and the landed bytes for every path capture order drops. Why: A path whose prepared bytes already contain the landed change keeps the prepared entry, matching what native sequential commits produce in a shared worktree. Setting the synthetic base to the landed content means the merge sees no landed change there.
replay_subsumption_text
Replay: the text half of subsumption over index-named blobs and hunks (replay_subsumption_text). What: The text half of replay’s subsumption: which regular-file paths hold prepared bytes that already contain the landed change. Why: A path is subsumed when the landed change applies in reverse to the prepared bytes with full context, or when the prepared change of every landed region is the landed change extended on one side. Hunks come from index-named single-level trees, so no patch header carries a user path, and binary detection is Git’s content rule (a NUL byte in the first 8000 bytes of any of the three blobs).
shadow_config
The shadow repository config file and the copied repository format. What: The shadow repository’s config file, written by cli-git itself, and the repository format facts it copies from the real common config. Why: Git does not apply core.repositoryformatversion and extensions.* from an included file, so they are copied explicitly. The shadow names no hooks directory (traditional hooks are unsupported, and every shadow command passes its own core.hooksPath); core.worktree, gc.auto and maintenance.auto follow the include, so the real config cannot redirect the worktree or start maintenance in the shadow; hook.<event>.enabled = false for every hook event follows it too, because the wrapper supports no external hook (src/shadow-repository/shadow-config.ts).
shadow_create
Creation of the shadow repository of one transaction. What: Creates the shadow repository of one published transaction: an empty bare repository, its config and alternates, the linked shared entries, the conclusion state, and the ref snapshot. Why: The shadow is a separate repository rather than a registered worktree, so git worktree list never shows it and preparation creates no ref in the real repository. Its object store receives the objects native git commit writes, and its alternates name the real object directory, so a real git prune cannot delete a pending commit (src/shadow-repository/shadow-repository.ts).
shadow_git
Git commands run against a transaction’s shadow repository. What: Git commands run against a transaction’s shadow repository, and its location and removal. Why: The shadow lives at <git-common-dir>/cli-git/shadow/<transaction-id>, derived from the transaction ID so recovery finds it before prepared.json exists. cli-git’s own shadow commands remove every variable that would redirect Git elsewhere and point hooks at an absent directory, so no hook observes private shadow writes (src/shadow-repository/shadow-refs.ts, runShadowGit).
shadow_links
The shadow repository links to the real shared entries. What: Links every non-private entry of the real common Git directory into a shadow repository, and copies the per-worktree entries (config.worktree, a linked worktree’s sparse checkout). Why: Shared entries such as hooks, info, rr-cache, lfs and modules must be the real ones, so hooks and native Git see them; transaction-private entries (refs, index, objects, conclusion state, lock files) stay the shadow’s own (src/shadow-repository/shadow-links.ts). On Windows the incumbent uses junctions and copies; this port uses directory symbolic links and copies, because the standard library has no junction API.
shadow_refs
The shadow ref store: snapshot, private target, symbolic refs and HEAD. What: The shadow ref store: a snapshot of every real ref, the private target ref, symbolic refs, and the private HEAD. Why: Hooks resolve tags, other branches and remote-tracking refs as they stood at invocation. With the files backend the snapshot is one packed-refs file and the private target is a loose ref, which takes precedence over a packed entry; with reftable the snapshot is one update-ref --stdin transaction (src/shadow-repository/shadow-refs.ts).
shadow_skeleton
The entries of an empty bare repository, created in-process instead of by git init. What: The files and directories of an empty bare repository on the files ref backend, created in-process. Why: The shadow repository used to be made by git init --bare --template=, a Git start whose whole effect is these few entries; create_shadow_repository overwrites the config it writes and every later shadow step sets the HEAD it writes, so nothing else of Git’s work is used. Creating them here removes one process start from every commit (init; the config read that follows it is the wrapper’s own and stays). A torn creation leaves a directory that is not a repository; recovery removes the shadow tree as a whole (binary_recovery_tearing_shadow_tests.rs), exactly as it does for a torn git init.