Skip to main content

Module conflict

Module conflict 

Source
Expand description

Conflict handling around commits and checkouts: side flags, saved copies of conflicted files and leftover markers. What: Conflict handling around commits and checkouts: side flags, saved copies of conflicted files and leftover markers. Why: These modules answer one question, what happens to a file that has conflict state.

In TS you’d write (pseudocode):

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

Modules§

autostash_carry
The stash and conflict stages Git’s apply of an autostash left in the commit’s scratch repository, carried back. What: Carrying back what Git’s apply of a merge’s autostash left in the commit’s scratch repository when the apply conflicted: the stash entry with its autostash reflog line, and the unmerged index entries of the files it conflicted in. Why: The commit that concludes a merge is built by real Git in a scratch repository, and Git’s apply_autostash runs inside it (builtin/commit.c line 1982). A stash that applies cleanly leaves nothing behind; one that conflicts is stored by git stash store in the scratch repository’s own refs/stash, and its conflict stages stay in the commit’s private index. Both were thrown away with the scratch directory, so Git’s promise (“Your changes are safe in the stash”) was false in the real repository. The objects need no copying: the scratch repository writes into the real object store. The stash entry is stored in the real repository with Git’s own words, and the stages are put into the index the landing installs, under the lock it holds.
command_conflict_side
The checkout and restore command lines that take one side of a conflicted file. What: Which git checkout and git restore command lines take one side of a conflicted file, and the paths they name. Why: During a merge, a rebase, a cherry-pick or a revert the usual way to settle a conflict is git checkout --ours|--theirs -- <path>, git checkout <rev> -- <path> or the git restore forms of the same. The linked-worktree policy rejects them as discarding forms; the conflict-side guard lets them through for conflicted paths after saving the file. Only a command line whose every token is understood qualifies: a form with --force, --patch, --pathspec-from-file, a branch option, an abbreviated git restore option, an index-only restore, or no -- before the paths stays rejected, because what it would discard is not known from the arguments alone.
config_discarded
The discardedCopies section of cli-git.config.jsonc. What: The discardedCopies section of cli-git.config.jsonc: how long and how much the folder of saved copies of conflicted files may keep (maxAgeDays, maxSize). Why: The settings of the wrapper live in one file with one validation, so a limit is a key there and not a second source in Git configuration. A value that is no limit (zero, negative, a fraction, text that is not a size) is a configuration failure that names the key, like every other bad value, and so is never read as “no limit” or as a zero that would remove every copy. Pruning itself is discarded_prune.rs.
conflict_markers
The marker lines a committed file still holds, and the line about an operation a commit left open. What: Which committed files still hold conflict marker lines, read from the committed content, and the one line that tells a person a commit of named paths left their merge open. Why: A commit of a path that was in conflict used to claim markers for every such path, so a file the person had resolved by editing (and not staged) was reported as full of markers although its committed blob held none, and the remedy it gave, another commit of the path, never finished the merge. The claim is now made only for a blob that holds a marker line as Git writes it, and the open merge is said on its own with the commands that finish it.
conflict_side_decision
Whether every token of a command line names a conflicted file. What: Whether every token of a command line names a conflicted file, read by its literal spelling. Why: A path wrongly judged conflicted lets a clean file be overwritten, so only a token that names exactly one file, below the working directory, with no wildcard or magic, can be allowed; every other token is refused and named.
conflict_side_guard
The linked-worktree policy’s carve-out for conflicted files during a merge, rebase, cherry-pick or revert. What: The linked-worktree policy’s carve-out for conflicted files: judge a git checkout or git restore command line during a merge, rebase, cherry-pick or revert, and save the files it would replace. Why: The owner decided (2026-11-02, “save, then allow”) that taking a side of a conflicted file is allowed once the current file is copied beside the audit log, and that every path that is not conflicted keeps the rejection. This file joins the pieces that decide and save (conflict_sides.rs, command_conflict_side.rs) to the repository: it finds the layout and the index in process, starts no Git, and returns what the policy should do. The copy is made here, before the policy lets the command run, so Git never starts before the copy is on disk.
conflict_side_modes
The pathspec modes and magic of a conflict-side line. What: The pathspec modes and the pathspec magic that make a conflict-side line unreadable to the guard, and the sentences that tell a person the same line without them would be saved and then allowed. Why: A mode (GIT_ICASE_PATHSPECS, --glob-pathspecs, …) changes which files a pathspec names, and magic (:(icase), :!, :/) does the same for one token, so the guard cannot say which files Git would replace and keeps the rejection. The rejection alone does not say what to change; when the line would be allowed without the mode or magic, the message does.
conflict_side_notice
The notices of a conflict-side command. What: The plain-language notices of a conflict-side command: the saved copies, and the clean paths of a refused line. Why: The person is told where each copy is before Git runs, and which paths to leave out when a line is refused.
conflict_side_source
Finding and copying the file a conflict-side command replaces. What: Finding the worktree file a conflict-side command is about to replace, and copying it. Why: The copy is the owner’s “save, then allow”: whatever Git is about to overwrite must be on disk first. Git writes dir/file by replacing whatever stands at dir (a symbolic link or a file) with a real directory, and by replacing the file as it is when Git runs. So the walk to the file never follows a link, a link or file in front of the name is a failure that names it, and a copy counts as saved only when the file it read is the file the name still holds and did not change while it was read.
conflict_side_state
The operation in progress and the conflicted paths. What: Which operation is in progress in a worktree’s Git directory, and which paths the index marks as conflicted. Why: Taking a side of a conflicted file is allowed only while a merge, a rebase, a cherry-pick or a revert waits, and only for paths with an unmerged index entry. Both are read in process, from the state files and the index file.
conflict_sides
The saved copy of each file a conflict-side command replaces. What: The saved copy of each file a conflict-side command replaces, and the one place that names the pieces of that carve-out: the operation and conflicted paths (conflict_side_state.rs), the decision on a command line (conflict_side_decision.rs), the notices (conflict_side_notice.rs) and the finding and reading of a file (conflict_side_source.rs). Why: linked-worktree-only rejects git checkout --theirs -- a.rs because it overwrites the worktree file. During a merge, a rebase, a cherry-pick or a revert that command is how a conflict is settled, and the file it overwrites is the half-resolved copy a person may have edited by hand. The owner’s decision is to let it through for conflicted paths after the current file is copied beside the audit log (discard_audit.rs), so nothing is lost and the copy is named. Everything here is read in process: the operation from the state files in the Git directory, the conflicted paths from the unmerged entries of the index file. The copy is written and synced before the caller lets Git run.
discard_audit
The append-only record of every command form that can discard uncommitted state. What: The append-only record of every command form that can discard uncommitted state: rejected, allowed because the worktree was clean, exempt, or run with the escape hatch. Why: When uncommitted work vanishes, nothing said which command did it, and the person who lost it blamed the wrong one. One line per decision, with the time, process, parent process, directory and arguments, makes a loss attributable. Writing the record never changes the outcome of the command.
discarded_prune
The bound on the folder of saved copies of conflicted files: age, size, audit and doctor report. What: The bound on <common git dir>/cli-git/discarded/: copies older than a number of days are removed, and the folder is kept under a size by removing the oldest copies first, never one younger than a day and never the copy just written. Each removed copy leaves one line in the audit file, and git cli-git doctor reports the folder. Why: The copies of conflicted files were never removed, so the folder grew for as long as the repository lived. They are the only remaining content of a file a command replaced, so the bound errs toward keeping: both limits are settings of cli-git.config.jsonc (discardedCopies.maxAgeDays, discardedCopies.maxSize, read by config_discarded.rs), a copy younger than a day is out of reach of both, and the pass runs only after a new copy is complete and durable (so a kill while copying costs the older copies nothing), and touches only directories named like the wrapper’s own (2026-11-02T14-01-07, with an optional -<number>). The folder is opened once without following a link and everything is read and removed through that descriptor (discarded_store.rs). No lock is taken: passes may overlap, and a file is counted and audited by the one pass whose removal of it succeeded, so overlapping passes split a directory’s files between their audit lines and every copy is audited once. A directory another pass removed first is not a problem. No commit waits on a pass. What a pass cannot do is kept and said, never skipped silently.
discarded_store
The folder of saved copies opened once without following a link, with every read and removal addressed through descriptors. What: The folder of saved copies (<common git dir>/cli-git/discarded) opened once without following a link, and every read and removal inside it addressed through descriptors: the folder’s, then each directory’s, never a path walked again. Why: A pass that lists a path and later removes a path can be led anywhere by a link or a rename that happens in between. Holding the folder and each directory open means a removal lands in the directory that was judged, a name that now stands for another directory is noticed by comparing what it is (device, inode and change time) with what the listing saw, and a link met anywhere inside is removed as a link and never entered. No lock keeps two passes from removing the same tree: each file has one owner, the pass whose unlinkat of it succeeded, and only that pass counts it, so passes that meet the same directory share its files and every file is counted once. A file or directory another pass already removed is not an error. The repository’s descriptor-relative module for the btrfs work is not on this branch yet; subvolume_anchor.rs widens the permissions of a directory it cannot enter, which a removal must never do.