mirror of
https://github.com/anthropics/claude-code.git
synced 2026-10-21 06:20:37 +08:00
* diff: the session's start asks nothing of the repository; /diff or the first edit pins it when it comes * diff: git runs when the built-in panel's would: one rev-parse at first need, the tree walked only for an open pane, nothing after a turn or a refused tool * diff: a shell command that failed or was cut short still refreshes an open pane, an edit that did opens nothing, and a probe /clear overtook pins nothing
80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
import type Backend from '../backend'
|
|
import Limits from '../limits'
|
|
import Argv from './argv'
|
|
import { FAILED_RUN } from './failed-run'
|
|
import { fetchDiff } from './fetch-diff'
|
|
import { fetchFileHunks } from './fetch-file-hunks'
|
|
import { GIT_BASE_MODES } from './git-base-modes'
|
|
import { GIT_WORDS } from './git-words'
|
|
import Probes from './probes'
|
|
import type Types from './types'
|
|
|
|
/**
|
|
* The git backend over the session's directory: the repository read with
|
|
* one `rev-parse` in that directory, then every child pinned to it.
|
|
*
|
|
* Each child runs with `--git-dir`, `--work-tree` and cwd the top, under
|
|
* the C locale and the fetch's timeout (the built-in's execPinnedGit); the
|
|
* first fetch reads the paths dirty then, once (Probes.dirtyPathsOf).
|
|
*
|
|
* @param host the bound host's runner and probes
|
|
* @returns the backend, or null outside a git working tree
|
|
*/
|
|
export async function gitBackendOf(
|
|
host: Backend.BackendHost,
|
|
): Promise<Backend.Backend | null> {
|
|
const runOf =
|
|
(pinned: Types.Repository | null): Types.GitRun =>
|
|
async argv => {
|
|
try {
|
|
return await host.run(
|
|
['git', ...(pinned ? Argv.pinnedLeadOf(pinned) : []), ...argv],
|
|
{
|
|
timeoutMs: Limits.GIT_TIMEOUT_MS,
|
|
env: Argv.GIT_CHILD_ENV,
|
|
...(pinned && { cwd: pinned.toplevel }),
|
|
},
|
|
)
|
|
} catch {
|
|
return FAILED_RUN
|
|
}
|
|
}
|
|
|
|
const repository = await Probes.repositoryOf(runOf(null))
|
|
|
|
if (!repository) {
|
|
return null
|
|
}
|
|
|
|
const run = runOf(repository)
|
|
|
|
let baseline: Promise<ReadonlySet<string> | null> | null = null
|
|
|
|
const depsOf = (dirty: ReadonlySet<string> | null): Types.GitDeps => ({
|
|
run,
|
|
repository,
|
|
mtimeOf: host.mtimeOf,
|
|
entryKindsOf: host.entryKindsOf,
|
|
sessionStartMs: host.sessionStartMsOf(),
|
|
baseline: dirty,
|
|
onBranchBase: host.onBranchBase,
|
|
})
|
|
|
|
return {
|
|
repository,
|
|
baseModes: GIT_BASE_MODES,
|
|
words: GIT_WORDS,
|
|
fetchDiff: async mode => {
|
|
baseline ??= Probes.dirtyPathsOf(run)
|
|
|
|
return fetchDiff(depsOf(await baseline), mode)
|
|
},
|
|
fetchFileHunks: (data, file) => fetchFileHunks(run, data, file),
|
|
headKeyOf: () =>
|
|
Probes.headKeyOf(
|
|
{ ...depsOf(null), readFile: host.readFile },
|
|
repository,
|
|
),
|
|
}
|
|
}
|