Path: blob/main/src/vs/platform/git/node/localGitService.ts
13394 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as cp from 'child_process';6import { CancellationError } from '../../../base/common/errors.js';7import { generateUuid } from '../../../base/common/uuid.js';8import { ILocalGitService } from '../common/localGitService.js';9import { ILogService } from '../../log/common/log.js';1011export class LocalGitService implements ILocalGitService {12declare readonly _serviceBrand: undefined;1314private _runningProcesses = new Map<string, cp.ChildProcess>();1516constructor(17@ILogService private readonly _logService: ILogService,18) { }1920private _exec(operationId: string, args: string[], cwd?: string): Promise<string> {21return new Promise((resolve, reject) => {22this._logService.trace(`[LocalGitService] git ${args.join(' ')}${cwd ? ` (cwd: ${cwd})` : ''}`);23const proc = cp.execFile('git', args, { cwd, encoding: 'utf8' }, (err, stdout, stderr) => {24if (!this._runningProcesses.delete(operationId)) {25reject(new CancellationError());26return;27}28if (err) {29this._logService.error(`[LocalGitService] git ${args[0]} failed:`, err.message, stderr);30reject(err);31return;32}33resolve(stdout);34});3536this._runningProcesses.set(operationId, proc);37});38}3940async clone(operationId: string, cloneUrl: string, targetPath: string, ref?: string): Promise<void> {41const args = ['clone'];42if (ref) {43args.push('--branch', ref);44}45args.push('--', cloneUrl, targetPath);46await this._exec(operationId, args);47}4849async pull(operationId: string, repoPath: string): Promise<boolean> {50const before = (await this._exec(operationId, ['rev-parse', 'HEAD'], repoPath)).trim();51await this._exec(operationId, ['pull', '--ff-only'], repoPath);52const after = (await this._exec(operationId, ['rev-parse', 'HEAD'], repoPath)).trim();53return before !== after;54}5556async checkout(operationId: string, repoPath: string, treeish: string, detached?: boolean): Promise<void> {57const args = detached58? ['checkout', '--detach', treeish]59: ['checkout', treeish];60await this._exec(operationId, args, repoPath);61}6263async revParse(repoPath: string, ref: string): Promise<string> {64return (await this._exec(generateUuid(), ['rev-parse', ref], repoPath)).trim();65}6667async fetch(operationId: string, repoPath: string): Promise<void> {68await this._exec(operationId, ['fetch'], repoPath);69}7071async revListCount(repoPath: string, fromRef: string, toRef: string): Promise<number> {72const result = await this._exec(generateUuid(), ['rev-list', '--count', `${fromRef}..${toRef}`], repoPath);73return Number(result.trim()) || 0;74}7576async cancel(operationId: string): Promise<void> {77const proc = this._runningProcesses.get(operationId);78if (proc) {79this._runningProcesses.delete(operationId);80proc.kill();81}82}83}848586