Skip to main content

Module worktree_remove

Module worktree_remove 

Source
Expand description

The removal of a clean subvolume worktree by one ioctl, and the plan of the git worktree remove it serves. What: The removal of a clean linked worktree that is a btrfs subvolume, by one subvolume destroy call and the deletion of its administrative directory, in place of Git’s file-by-file removal. Why: Git unlinks every file of the worktree (0.7 s without ignored state, 3.6 s with a large ignored tree in the measurements of doc/planning/cli-git-btrfs-worktree.md), and the subvolume call takes milliseconds. The call cannot be undone, so the wrapper takes it only when the same conditions hold that make Git remove without --force: the worktree is registered in the repository the command runs in, under the name Git would pick, is not locked, is clean (worktree_clean.rs), and holds no submodule. The mount must also allow the call to an unprivileged user (user_subvol_rm_allowed). Every other case, and every call that the kernel refuses, is left to Git, which then words the refusal itself.

The check and the destroy are not one step, as Git’s check and its deletion are not. Three things keep the window small and its worst case no worse than Git’s: the directories are held open from before the proof of cleanliness to the destroy and the destroy names the subvolume by id (or by name below the held parent), the lock, the identity of the worktree directory and of the registration are looked at again immediately before the destroy, and the registration is emptied through its held descriptor, never by a path that could name another directory by then. What remains is a write or a lock made by another process in the milliseconds between the last look and the destroy; Git has the same window for its whole deletion, which takes seconds (SPEC.md).

In TS you’d write (pseudocode):

const outcome = await removeSubvolumeWorktree(request); // 'left-to-git': run git worktree remove

Structs§

Held
What: The directories one removal holds open from before the proof of cleanliness to the destroy, and the identities they had when they were looked at. Why: A descriptor names the object it was opened on, whatever happens to the path afterwards; the identities let the last look before the destroy tell a swapped name from the held object.
LinuxOperations
The kernel and Git, as they are.
RemoveRequest
What: What one removal is asked to do and in which repository. Why: The repository that was invoked decides which registrations count; the worktree’s own pointers never do.

Enums§

RemoveOutcome
What: How one attempt to remove a worktree with a subvolume destroy ended. Why: Three endings need three different next steps: Git removes it (nothing changed), the work is done, or the files are gone and the registration is not, which only the person can finish and which must never reach Git.

Constants§

DESTROY_NOTICE
What the command says on standard error whenever it destroys a subvolume.

Traits§

RemoveOperations
What: The operations of one removal that touch the kernel or start Git, behind one trait. &self borrows the implementation read-only; dyn RemoveOperations is how a caller holds “any implementation” (a TS interface). Why: The ordering of the checks is the same on any filesystem; a stand-in lets the controls run it on a plain directory tree, and swap objects between two steps to prove the identity checks.

Functions§

remove_subvolume_worktree
What: Remove the worktree if every condition holds, with the kernel and Git as they are. Why: See remove_with.
remove_with
What: Remove the worktree if every condition holds; report how it ended. Why: LeftToGit means Git has to do the removal, and nothing was changed.