mirror of
https://github.com/stablyai/orca.git
synced 2026-09-23 00:02:29 +00:00
Four copies of the same loop ran `git remote` and then a serial `git remote get-url <name>` per remote to answer "which remote has this URL". On a repo with 58 remotes that is 59 subprocesses -- measured at 1083 ms -- for one question, and worktree create asks it several times. `git remote -v` answers for every remote from one child, reporting the same insteadOf-expanded first fetch URL `get-url` prints. The batched `cat-file --batch-check` branch-conflict probe decides from stdout, but its WSL route was unfenced, so a login-shell fallback printed the distro banner onto the stream it parses. That broke the one-line-per-ref contract, made every batch undecided, and fell straight back to one `show-ref` per remote -- the cost the batch exists to remove. Measured at 58 remotes / 4346 branches, spawns and wall time: push-target remote scan 59 -> 1 (1083 ms -> 8 ms) branch-conflict probe 60 -> 3 (984 ms -> 43 ms) configured push target 123 -> 6 (2707 ms -> 157 ms)
65 lines
2.5 KiB
TypeScript
65 lines
2.5 KiB
TypeScript
// Why: "which remote has this URL?" was answered with one `git remote get-url`
|
|
// subprocess per remote, awaited serially -- 58 spawns on a repo with 58 remotes,
|
|
// on every push-target resolution. `git remote -v` answers for every remote from
|
|
// one child.
|
|
//
|
|
// `remote -v` is the faithful one-command form, not `config --get-regexp '^remote\.'`:
|
|
// both `remote -v` and `remote get-url` print the URL *after* `url.<base>.insteadOf`
|
|
// expansion and pick the first of several `remote.<name>.url` values, while raw config
|
|
// reads return the unexpanded value and the last of the multiple values.
|
|
//
|
|
// `remote -v` also predates `remote get-url` (2.7), so this lowers rather than raises
|
|
// the Git floor and needs no capability gate.
|
|
|
|
import { iterateProcessOutputLines } from './process-output-field-scanner'
|
|
|
|
export type GitRemoteVerboseEntry = {
|
|
name: string
|
|
url: string
|
|
direction: 'fetch' | 'push'
|
|
}
|
|
|
|
// Greedy prefix so a URL containing spaces or parentheses keeps them.
|
|
const REMOTE_VERBOSE_URL_PATTERN = /^(.*) \((fetch|push)\)$/
|
|
|
|
/** Parse one `<name>\t<url> (fetch|push)` row. */
|
|
export function parseGitRemoteVerboseLine(line: string): GitRemoteVerboseEntry | null {
|
|
const tabIndex = line.indexOf('\t')
|
|
if (tabIndex === -1) {
|
|
return null
|
|
}
|
|
const name = line.slice(0, tabIndex)
|
|
const match = REMOTE_VERBOSE_URL_PATTERN.exec(line.slice(tabIndex + 1).trim())
|
|
return match ? { name, url: match[1], direction: match[2] as 'fetch' | 'push' } : null
|
|
}
|
|
|
|
/**
|
|
* Fetch URL per remote in `git remote` order -- the value `git remote get-url <name>`
|
|
* prints. A remote configured with only a `pushurl` has no fetch row and is absent
|
|
* here; `get-url` echoed the remote's own name for it, which no caller can match.
|
|
*/
|
|
export function parseGitRemoteFetchUrls(stdout: string): Map<string, string> {
|
|
const fetchUrls = new Map<string, string>()
|
|
for (const line of iterateProcessOutputLines(stdout)) {
|
|
const parsed = parseGitRemoteVerboseLine(line)
|
|
// First wins: `get-url` without `--all` prints the first `remote.<name>.url`.
|
|
if (parsed?.direction === 'fetch' && !fetchUrls.has(parsed.name)) {
|
|
fetchUrls.set(parsed.name, parsed.url)
|
|
}
|
|
}
|
|
return fetchUrls
|
|
}
|
|
|
|
/** First remote whose fetch URL matches, in the order the per-remote scan visited them. */
|
|
export function findGitRemoteNameByFetchUrl(
|
|
stdout: string,
|
|
matchesUrl: (url: string) => boolean
|
|
): string | null {
|
|
for (const [name, url] of parseGitRemoteFetchUrls(stdout)) {
|
|
if (matchesUrl(url)) {
|
|
return name
|
|
}
|
|
}
|
|
return null
|
|
}
|