You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
discard-cache (and finish --discard-cache, sweep) treats every ignored entry Git reports
(status --ignored=matching, file or directory) as disposable, unless the repository's keep
file keeps it or it is or holds a repository. An ignored entry no structural rule recognises
is discarded as the new kind ignored-output instead of retained. This reverses "anything
unrecognised is retained": a record written into an ignored directory (target/backlog-input/,
for instance) is deleted unless the keep file keeps it.
The keep file is .worktreekeep at the tree root. Its lines are Git exclude patterns matched
by Git's own exclude engine (git ls-files --others --ignored --exclude-from), so negation,
directory-only patterns and anchoring mean what they mean in .gitignore; a path is kept when
a pattern matches it or one of its ancestors, and a directory a pattern names is kept even
when it holds no file (a parent Git lists only because everything in it matches is not). Git
cannot re-include a path below an excluded
directory, so !dir/file after dir/ keeps dir/file too; write dir/* to let a negation
take effect. An absent keep file keeps nothing. A symbolic link, a directory or an unreadable
file there refuses the discard as keep-file-invalid and deletes nothing. The keep file itself
is never deleted, even when Git ignores it. Kept files are reported one by one in retained_ignored.
A repository is retained whole: an entry named .git, a directory holding one directly, or a
Git directory. So is a mount point (read from /proc/self/mountinfo on Linux, so a bind mount
from the same filesystem counts; elsewhere only another device does), an entry on another
device, and one that cannot be read: a directory whose names cannot be listed or a regular file
this user cannot open. A directory holding any of these, or a kept path, at any depth is never
deleted whole, whatever kind it is: it falls to its direct entries, each classified by the same
rule. 0.17.1 retained a profile, node_modules,
virtual environment, tool cache or Flutter output directory holding a repository whole; each
now falls to its parts.
A Cargo target holding anything but Cargo's layout falls to its parts: profiles stay cargo-profile, tmp/ stays cargo-target-tmp, and its CACHEDIR.TAG, .rustc_info.json
and everything else are discarded as ignored-output.
A symbolic link is deleted itself and never followed, and a deletion is refused as cache-state-changed when a directory above the entry is no longer a real directory. An
ignored path that is not UTF-8 refuses the discard as cache-path-not-utf8 before anything is
deleted, since the report could not name it.
The keep file, read again and scoped to the entry, the mount table and the walk for
repositories are repeated immediately before each deletion.
archive (and so finish --archive and a sweep's archive) reads the keep file too: a kept path
is never build layout, so it stays in dirty.patch even below a recognised cargo target or
Flutter output directory, and finish --discard-cache --archive archives every kept record.
A keep file that is not a readable regular file keeps every path there, so archive leaves
nothing out; it does not refuse. Removal through a worktree.archive/3 archive deletes a
left-out file only while it is not kept and the keep file's bytes are those it was split with.
ignored-output is a new kind value; the CLI JSON protocol stays 4 and no field changes. archive never modifies the tree; sweep never removes a tree.
prune-archives --strip-build-output also strips ignored output from existing archives: a
section that purely adds an untracked file the keep file does not keep, whose path Git's
exclude engine ignores under both HEAD's .gitignore files (read from Git) and the tree's as
archived (HEAD's with the patch's .gitignore additions, modifications and deletions applied).
A path the tree's own .gitignore change un-ignored stays; where those changes cannot be
applied, nothing at or below the touched file's directory is stripped. A non-layout file below
an ignored target/, node_modules/ or build/ is stripped now; 0.17.1 kept it.
Neither info/exclude nor any core.excludesFile is read: either may have changed since the
archive was written, so a path only they ignore stays. Each rule set is asked in one git check-ignore --no-index --stdin -z over a scratch work tree in the system's temporary
directory, removed on every path out; a dry-run writes nothing below the archive root.
The strip never strips a path the keep file keeps, layout or ignored output. The keep file is
read from HEAD's tree, or from the patch when it purely adds .worktreekeep (that section
stays). A patch that changes a tracked keep file, or a keep file in HEAD or the patch that is
not a regular file (a symbolic link, a gitlink) or holds a NUL byte, keeps every path.
Repository content (a .git component, or a Git directory the patch shows) stays whatever the
rules say.
Stripped ignored output is recorded as a build_output target of origin strip, per outermost
directory both rule sets ignore that HEAD does not hold and that holds no path whose section
stays, or per file. The archive format stays worktree.archive/3 and the CLI JSON protocol
stays 4.