fetch.ts•1.93 kB
/**
* @fileoverview CLI provider git fetch operation
* @module services/git/providers/cli/operations/remotes/fetch
*/
import type { RequestContext } from '@/utils/index.js';
import type {
GitFetchOptions,
GitFetchResult,
GitOperationContext,
} from '../../../../types.js';
import { buildGitCommand, mapGitError } from '../../utils/index.js';
/**
* Execute git fetch to download remote changes.
*/
export async function executeFetch(
options: GitFetchOptions,
context: GitOperationContext,
execGit: (
args: string[],
cwd: string,
ctx: RequestContext,
) => Promise<{ stdout: string; stderr: string }>,
): Promise<GitFetchResult> {
try {
const args: string[] = [];
const remote = options.remote || 'origin';
args.push(remote);
if (options.prune) {
args.push('--prune');
}
if (options.tags) {
args.push('--tags');
}
if (options.depth) {
args.push(`--depth=${options.depth}`);
}
const cmd = buildGitCommand({ command: 'fetch', args });
const gitOutput = await execGit(
cmd,
context.workingDirectory,
context.requestContext,
);
// Parse fetched and pruned refs from output
const fetchedRefs: string[] = [];
const prunedRefs: string[] = [];
const lines = gitOutput.stderr.split('\n'); // git fetch outputs to stderr
for (const line of lines) {
if (line.includes('->')) {
const match = line.match(/\*\s+\[new branch\]\s+(\S+)/);
if (match) {
fetchedRefs.push(match[1]!);
}
}
if (line.includes('pruned')) {
const match = line.match(/x\s+\[deleted\]\s+.*?\s+(\S+)/);
if (match) {
prunedRefs.push(match[1]!);
}
}
}
const result = {
success: true,
remote,
fetchedRefs,
prunedRefs,
};
return result;
} catch (error) {
throw mapGitError(error, 'fetch');
}
}