Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
commands,git: check for prunable worktrees
The GetAllWorktrees() function in our "git" package was introduced as part of the implementation of the "git lfs prune" command in PR git-lfs#742. This function examines the contents of a repository's ".git/worktrees" folder and returns an array of Worktree structures for any linked working trees it finds, plus one Worktree structure for the main working tree, if one exists. The "git lfs prune" command then checks these working trees' current Git references and indexes for any Git LFS objects it should retain in the Git LFS object cache. In subsequent commits in this PR we expect to add an alternative implementation of the GetAllWorktrees() function which uses the "git worktree list" command, as this will ensure we remain compatible with some forthcoming changes in Git that will alter the contents of the "gitdir" files in ".git/worktrees" hierarchy. We will need to retain the legacy implementation of the GetAllWorktrees() function as well, as prior to Git version 2.36.0 the "git worktree list" command is either not available or does not support the full set of options we will require. The "git worktree list" command reports when a linked working tree no longer exists and so its data in the ".git/worktrees" hierarchy could be pruned with the "git worktree prune" command. Our new implementation of the GetAllWorktrees() function will therefore be able to return this prunable state as a flag in the Worktree structure. The pruneTaskGetRetainedIndex() function run by our "git lfs prune" command calls the ScanIndex() method of the GitScanner structure in our "lfs" package, whose internal functions then create two DiffIndexScanner structures and invoke their Scan() methods repeatedly. That structure's initialization function, NewDiffIndexScanner(), uses the DiffIndex() function in our "git" package to start a "git diff-index" command and pipe its output into a buffer, which is then consumed by the DiffIndexScanner's Scan() method. As we run these "git diff-index" commands in each linked working tree, if it no longer actually exists, the commands simply fail. We silently ignore these failures because the DiffIndex() function uses the gitBufferedStdout() function to start the command, and that discards the stderr stream, we never call the Wait() method of the underlying Cmd structure from the "os/exec" package, so we also discard the exit code from the "git diff-index" command. However, we can avoid running unnecessary "git diff-index" commands entirely if we detect that a linked working tree no longer exists. As this will be straightforward in our new implementation of the GetAllWorktrees() function, we first update our existing version of the function to perform a check similar to one made by Git, and return a true flag value in our Worktree structure if the working tree is missing. We add a Prunable flag to the Worktree structure, and check it in the pruneTaskGetRetainedWorktree() function so we only run the pruneTaskGetRetainedIndex() function if a linked working tree's Prunable flag is false. We then expand our existing TestWorktrees() test function to validate that when a linked working tree is removed, the Prunable flag is set as we expect. Note that our "prune worktree" test in the t/t-prune-worktree.sh test script already performs checks of our "git lfs prune" command after a linked working tree is removed. These checks pass without the changes in this commit because the "git diff-index" commands we try to run in the working tree simply fail, and we then ignore those failures. With the changes in this commit, the behaviour of the "git lfs prune" command remains the same, but it no longer tries to run "git diff-index" in non-extant working trees.
- Loading branch information