pull.ts•2.01 kB
/**
* @fileoverview CLI provider git pull operation
* @module services/git/providers/cli/operations/remotes/pull
*/
import type { RequestContext } from '@/utils/index.js';
import type {
GitOperationContext,
GitPullOptions,
GitPullResult,
} from '../../../../types.js';
import { buildGitCommand, mapGitError } from '../../utils/index.js';
/**
* Execute git pull to fetch and integrate remote changes.
*/
export async function executePull(
options: GitPullOptions,
context: GitOperationContext,
execGit: (
args: string[],
cwd: string,
ctx: RequestContext,
) => Promise<{ stdout: string; stderr: string }>,
): Promise<GitPullResult> {
try {
const args: string[] = [];
const remote = options.remote || 'origin';
args.push(remote);
if (options.branch) {
args.push(options.branch);
}
if (options.rebase) {
args.push('--rebase');
}
if (options.fastForwardOnly) {
args.push('--ff-only');
}
const cmd = buildGitCommand({ command: 'pull', args });
const result = await execGit(
cmd,
context.workingDirectory,
context.requestContext,
);
// Determine strategy
let strategy: 'merge' | 'rebase' | 'fast-forward' = 'merge';
if (options.rebase) {
strategy = 'rebase';
} else if (result.stdout.includes('Fast-forward')) {
strategy = 'fast-forward';
}
// Check for conflicts
const hasConflicts =
result.stdout.includes('CONFLICT') || result.stderr.includes('CONFLICT');
// Parse changed files
const filesChanged = result.stdout
.split('\n')
.filter((line) => line.trim() && !line.includes('CONFLICT'))
.map((line) => line.trim())
.filter((f) => f);
const pullResult = {
success: !hasConflicts,
remote,
branch: options.branch || 'HEAD',
strategy,
conflicts: hasConflicts,
filesChanged,
};
return pullResult;
} catch (error) {
throw mapGitError(error, 'pull');
}
}