* Stage every working-tree change. Walks the status matrix and * splits the work: present-but-changed paths go through `add`, * worktree-deleted paths go through `remove` (which `add` cannot * express). The status-matrix tuple is `[path, head, workdir, * stage]`; `workdir === 0` means the file i
(opts: AddWithDeps, dir: string)
| 106 | * stage]`; `workdir === 0` means the file is gone from disk. |
| 107 | */ |
| 108 | async function addAll(opts: AddWithDeps, dir: string): Promise<void> { |
| 109 | let matrix: StatusMatrixRow[]; |
| 110 | try { |
| 111 | matrix = await opts.git.statusMatrix({ fs: opts.fs, dir, cache: opts.cache }); |
| 112 | } catch (cause) { |
| 113 | if (isNotARepositoryCause(cause)) throw new NotARepositoryError(dir, { cause }); |
| 114 | throw new GitError("EADDFAIL", `git add failed: ${errorMessage(cause)}`, { cause }); |
| 115 | } |
| 116 | |
| 117 | const toAdd: string[] = []; |
| 118 | const toRemove: string[] = []; |
| 119 | for (const [filepath, head, workdir, stage] of matrix) { |
| 120 | // `commit -a` semantics: only touch paths already in HEAD, |
| 121 | // so untracked files (head === 0) are left alone. |
| 122 | if (opts.trackedOnly && head !== 1) continue; |
| 123 | if (workdir === 0) { |
| 124 | // Gone from the working tree. Remove any staged entry so |
| 125 | // the index matches the absence on disk. trackedOnly above |
| 126 | // keeps `commit -a` from touching staged-but-untracked paths. |
| 127 | if (stage !== 0) toRemove.push(filepath); |
| 128 | continue; |
| 129 | } |
| 130 | // Present on disk and differs from the staged copy. |
| 131 | if (workdir !== 1 || stage !== 1) toAdd.push(filepath); |
| 132 | } |
| 133 | |
| 134 | try { |
| 135 | if (toAdd.length > 0) { |
| 136 | await opts.git.add({ |
| 137 | fs: opts.fs, |
| 138 | dir, |
| 139 | filepath: toAdd, |
| 140 | cache: opts.cache, |
| 141 | force: opts.force, |
| 142 | }); |
| 143 | } |
| 144 | for (const filepath of toRemove) { |
| 145 | await opts.git.remove({ fs: opts.fs, dir, filepath, cache: opts.cache }); |
| 146 | } |
| 147 | } catch (cause) { |
| 148 | if (isNotARepositoryCause(cause)) throw new NotARepositoryError(dir, { cause }); |
| 149 | throw new GitError("EADDFAIL", `git add failed: ${errorMessage(cause)}`, { cause }); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | export interface GitRmOptions { |
| 154 | /** Working-tree directory inside the VFS. Defaults to `/`. */ |
no test coverage detected