mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-13 05:12:55 -07:00
Merge branch 'main' into package-lock-update
This commit is contained in:
@@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* @license
|
||||||
|
* Copyright 2025 Google LLC
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||||
|
import * as fs from 'node:fs/promises';
|
||||||
|
import * as path from 'node:path';
|
||||||
|
import * as os from 'node:os';
|
||||||
|
import { GitService, Storage } from '@google/gemini-cli-core';
|
||||||
|
|
||||||
|
describe('Checkpointing Integration', () => {
|
||||||
|
let tmpDir: string;
|
||||||
|
let projectRoot: string;
|
||||||
|
let fakeHome: string;
|
||||||
|
let originalEnv: NodeJS.ProcessEnv;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tmpDir = await fs.mkdtemp(
|
||||||
|
path.join(os.tmpdir(), 'gemini-checkpoint-test-'),
|
||||||
|
);
|
||||||
|
projectRoot = path.join(tmpDir, 'project');
|
||||||
|
fakeHome = path.join(tmpDir, 'home');
|
||||||
|
|
||||||
|
await fs.mkdir(projectRoot, { recursive: true });
|
||||||
|
await fs.mkdir(fakeHome, { recursive: true });
|
||||||
|
|
||||||
|
// Save original env
|
||||||
|
originalEnv = { ...process.env };
|
||||||
|
|
||||||
|
// Simulate environment with NO global gitconfig
|
||||||
|
process.env['HOME'] = fakeHome;
|
||||||
|
delete process.env['GIT_CONFIG_GLOBAL'];
|
||||||
|
delete process.env['GIT_CONFIG_SYSTEM'];
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
// Restore env
|
||||||
|
process.env = originalEnv;
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
try {
|
||||||
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to cleanup temp dir', e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully create and restore snapshots without global git config', async () => {
|
||||||
|
const storage = new Storage(projectRoot);
|
||||||
|
const gitService = new GitService(projectRoot, storage);
|
||||||
|
|
||||||
|
// 1. Initialize
|
||||||
|
await gitService.initialize();
|
||||||
|
|
||||||
|
// Verify system config empty file creation
|
||||||
|
// We need to access getHistoryDir logic or replicate it.
|
||||||
|
// Since we don't have access to private getHistoryDir, we can infer it or just trust the functional test.
|
||||||
|
|
||||||
|
// 2. Create initial state
|
||||||
|
await fs.writeFile(path.join(projectRoot, 'file1.txt'), 'version 1');
|
||||||
|
await fs.writeFile(path.join(projectRoot, 'file2.txt'), 'permanent file');
|
||||||
|
|
||||||
|
// 3. Create Snapshot
|
||||||
|
const snapshotHash = await gitService.createFileSnapshot('Checkpoint 1');
|
||||||
|
expect(snapshotHash).toBeDefined();
|
||||||
|
|
||||||
|
// 4. Modify files
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(projectRoot, 'file1.txt'),
|
||||||
|
'version 2 (BAD CHANGE)',
|
||||||
|
);
|
||||||
|
await fs.writeFile(
|
||||||
|
path.join(projectRoot, 'file3.txt'),
|
||||||
|
'new file (SHOULD BE GONE)',
|
||||||
|
);
|
||||||
|
await fs.rm(path.join(projectRoot, 'file2.txt'));
|
||||||
|
|
||||||
|
// 5. Restore
|
||||||
|
await gitService.restoreProjectFromSnapshot(snapshotHash);
|
||||||
|
|
||||||
|
// 6. Verify state
|
||||||
|
const file1Content = await fs.readFile(
|
||||||
|
path.join(projectRoot, 'file1.txt'),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
|
expect(file1Content).toBe('version 1');
|
||||||
|
|
||||||
|
const file2Exists = await fs
|
||||||
|
.stat(path.join(projectRoot, 'file2.txt'))
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
expect(file2Exists).toBe(true);
|
||||||
|
const file2Content = await fs.readFile(
|
||||||
|
path.join(projectRoot, 'file2.txt'),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
|
expect(file2Content).toBe('permanent file');
|
||||||
|
|
||||||
|
const file3Exists = await fs
|
||||||
|
.stat(path.join(projectRoot, 'file3.txt'))
|
||||||
|
.then(() => true)
|
||||||
|
.catch(() => false);
|
||||||
|
expect(file3Exists).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore user global git config and use isolated identity', async () => {
|
||||||
|
// 1. Create a fake global gitconfig with a specific user
|
||||||
|
const globalConfigPath = path.join(fakeHome, '.gitconfig');
|
||||||
|
const globalConfigContent = `[user]
|
||||||
|
name = Global User
|
||||||
|
email = global@example.com
|
||||||
|
`;
|
||||||
|
await fs.writeFile(globalConfigPath, globalConfigContent);
|
||||||
|
|
||||||
|
// Point HOME to fakeHome so git picks up this global config (if we didn't isolate it)
|
||||||
|
process.env['HOME'] = fakeHome;
|
||||||
|
// Ensure GIT_CONFIG_GLOBAL is NOT set for the process initially,
|
||||||
|
// so it would default to HOME/.gitconfig if GitService didn't override it.
|
||||||
|
delete process.env['GIT_CONFIG_GLOBAL'];
|
||||||
|
|
||||||
|
const storage = new Storage(projectRoot);
|
||||||
|
const gitService = new GitService(projectRoot, storage);
|
||||||
|
|
||||||
|
await gitService.initialize();
|
||||||
|
|
||||||
|
// 2. Create a file and snapshot
|
||||||
|
await fs.writeFile(path.join(projectRoot, 'test.txt'), 'content');
|
||||||
|
await gitService.createFileSnapshot('Snapshot with global config present');
|
||||||
|
|
||||||
|
// 3. Verify the commit author in the shadow repo
|
||||||
|
const historyDir = storage.getHistoryDir();
|
||||||
|
|
||||||
|
const { execFileSync } = await import('node:child_process');
|
||||||
|
|
||||||
|
const logOutput = execFileSync(
|
||||||
|
'git',
|
||||||
|
['log', '-1', '--pretty=format:%an <%ae>'],
|
||||||
|
{
|
||||||
|
cwd: historyDir,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
GIT_DIR: path.join(historyDir, '.git'),
|
||||||
|
GIT_CONFIG_GLOBAL: path.join(historyDir, '.gitconfig'),
|
||||||
|
GIT_CONFIG_SYSTEM: path.join(historyDir, '.gitconfig_system_empty'),
|
||||||
|
},
|
||||||
|
encoding: 'utf-8',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(logOutput).toBe('Gemini CLI <gemini-cli@google.com>');
|
||||||
|
expect(logOutput).not.toContain('Global User');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -72,6 +72,13 @@ export async function setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function teardown() {
|
export async function teardown() {
|
||||||
|
// Disable mouse tracking
|
||||||
|
if (process.stdout.isTTY) {
|
||||||
|
process.stdout.write(
|
||||||
|
'\x1b[?1000l\x1b[?1003l\x1b[?1015l\x1b[?1006l\x1b[?1002l',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup the test run directory unless KEEP_OUTPUT is set
|
// Cleanup the test run directory unless KEEP_OUTPUT is set
|
||||||
if (process.env['KEEP_OUTPUT'] !== 'true' && runDir) {
|
if (process.env['KEEP_OUTPUT'] !== 'true' && runDir) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -367,7 +367,7 @@ export async function main() {
|
|||||||
) {
|
) {
|
||||||
settings.setValue(
|
settings.setValue(
|
||||||
SettingScope.User,
|
SettingScope.User,
|
||||||
'selectedAuthType',
|
'security.auth.selectedType',
|
||||||
AuthType.COMPUTE_ADC,
|
AuthType.COMPUTE_ADC,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,42 +36,3 @@ export const tinyAsciiLogo = `
|
|||||||
███░ ░░█████████
|
███░ ░░█████████
|
||||||
░░░ ░░░░░░░░░
|
░░░ ░░░░░░░░░
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const shortAsciiLogoIde = `
|
|
||||||
░░░░░░░░░ ░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░
|
|
||||||
░░░ ░░░ ░░░ ░░░░░░ ░░░░░░ ░░░ ░░░░░░ ░░░░░ ░░░
|
|
||||||
░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░
|
|
||||||
█████████░░██████████ ██████ ░░██████░█████░██████ ░░█████ █████░
|
|
||||||
███░░ ███░███░░ ██████ ░██████░░███░░██████ ░█████ ███░░
|
|
||||||
███░░ ░░███░░ ███░███ ███ ███░░███░░███░███ ███░░ ███░░
|
|
||||||
███░░░░████░██████░░░░░███░░█████ ███░░███░░███░░███ ███░░░ ███░░░
|
|
||||||
███ ███ ███ ███ ███ ███ ███ ███ ██████ ███
|
|
||||||
███ ███ ███ ███ ███ ███ ███ █████ ███
|
|
||||||
█████████ ██████████ ███ ███ █████ ███ █████ █████
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const longAsciiLogoIde = `
|
|
||||||
░░░ ░░░░░░░░░ ░░░░░░░░░░ ░░░░░░ ░░░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░
|
|
||||||
░░░ ░░░ ░░░ ░░░ ░░░░░░ ░░░░░░ ░░░ ░░░░░░ ░░░░░ ░░░
|
|
||||||
░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░ ░░░
|
|
||||||
███ ░░░ █████████░░██████████ ██████ ░░██████░█████░██████ ░░█████ █████░
|
|
||||||
███ ░░░ ███░ ███░███░░ ██████ ░██████░░███░░██████ ░█████ ███░░
|
|
||||||
███ ███░░░ ░░███░░ ███░███ ███ ███░░███░░███░███ ███░░ ███░░
|
|
||||||
░░░ ███ ███ ░░░█████░██████░░░░░███░░█████ ███░░███░░███░░███ ███░░░ ███░░░
|
|
||||||
███ ███ ███ ███ ███ ███ ███ ███ ███ ██████ ███
|
|
||||||
███ ███ ███ ███ ███ ███ ███ ███ █████ ███
|
|
||||||
███ █████████ ██████████ ███ ███ █████ ███ █████ █████
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const tinyAsciiLogoIde = `
|
|
||||||
░░░ ░░░░░░░░░
|
|
||||||
░░░ ░░░ ░░░
|
|
||||||
░░░ ░░░
|
|
||||||
███ ░░░ █████████░░░
|
|
||||||
███ ░░░ ███░░ ███░░
|
|
||||||
███ ███░░ ░░░
|
|
||||||
░░░ ███ ███░░░░████░
|
|
||||||
███ ███ ███
|
|
||||||
███ ███ ███
|
|
||||||
███ █████████
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ import { render } from '../../test-utils/render.js';
|
|||||||
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest';
|
||||||
import { Header } from './Header.js';
|
import { Header } from './Header.js';
|
||||||
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
import * as useTerminalSize from '../hooks/useTerminalSize.js';
|
||||||
import { longAsciiLogo, longAsciiLogoIde } from './AsciiArt.js';
|
import { longAsciiLogo } from './AsciiArt.js';
|
||||||
import * as semanticColors from '../semantic-colors.js';
|
import * as semanticColors from '../semantic-colors.js';
|
||||||
import * as terminalSetup from '../utils/terminalSetup.js';
|
|
||||||
import { Text } from 'ink';
|
import { Text } from 'ink';
|
||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
|
|
||||||
@@ -18,9 +17,6 @@ vi.mock('../hooks/useTerminalSize.js');
|
|||||||
vi.mock('../hooks/useSnowfall.js', () => ({
|
vi.mock('../hooks/useSnowfall.js', () => ({
|
||||||
useSnowfall: vi.fn((art) => art),
|
useSnowfall: vi.fn((art) => art),
|
||||||
}));
|
}));
|
||||||
vi.mock('../utils/terminalSetup.js', () => ({
|
|
||||||
getTerminalProgram: vi.fn(),
|
|
||||||
}));
|
|
||||||
vi.mock('ink-gradient', () => {
|
vi.mock('ink-gradient', () => {
|
||||||
const MockGradient = ({ children }: { children: React.ReactNode }) => (
|
const MockGradient = ({ children }: { children: React.ReactNode }) => (
|
||||||
<>{children}</>
|
<>{children}</>
|
||||||
@@ -41,7 +37,6 @@ vi.mock('ink', async () => {
|
|||||||
describe('<Header />', () => {
|
describe('<Header />', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
vi.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue(null);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders the long logo on a wide terminal', () => {
|
it('renders the long logo on a wide terminal', () => {
|
||||||
@@ -58,22 +53,6 @@ describe('<Header />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses the IDE logo when running in an IDE', () => {
|
|
||||||
vi.spyOn(useTerminalSize, 'useTerminalSize').mockReturnValue({
|
|
||||||
columns: 120,
|
|
||||||
rows: 20,
|
|
||||||
});
|
|
||||||
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue('vscode');
|
|
||||||
|
|
||||||
render(<Header version="1.0.0" nightly={false} />);
|
|
||||||
expect(Text).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
children: longAsciiLogoIde,
|
|
||||||
}),
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('renders custom ASCII art when provided', () => {
|
it('renders custom ASCII art when provided', () => {
|
||||||
const customArt = 'CUSTOM ART';
|
const customArt = 'CUSTOM ART';
|
||||||
render(
|
render(
|
||||||
@@ -87,24 +66,13 @@ describe('<Header />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('renders custom ASCII art as is when running in an IDE', () => {
|
|
||||||
const customArt = 'CUSTOM ART';
|
|
||||||
vi.mocked(terminalSetup.getTerminalProgram).mockReturnValue('vscode');
|
|
||||||
render(
|
|
||||||
<Header version="1.0.0" nightly={false} customAsciiArt={customArt} />,
|
|
||||||
);
|
|
||||||
expect(Text).toHaveBeenCalledWith(
|
|
||||||
expect.objectContaining({
|
|
||||||
children: customArt,
|
|
||||||
}),
|
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('displays the version number when nightly is true', () => {
|
it('displays the version number when nightly is true', () => {
|
||||||
render(<Header version="1.0.0" nightly={true} />);
|
render(<Header version="1.0.0" nightly={true} />);
|
||||||
const textCalls = (Text as Mock).mock.calls;
|
const textCalls = (Text as Mock).mock.calls;
|
||||||
expect(textCalls[1][0].children.join('')).toBe('v1.0.0');
|
const versionText = Array.isArray(textCalls[1][0].children)
|
||||||
|
? textCalls[1][0].children.join('')
|
||||||
|
: textCalls[1][0].children;
|
||||||
|
expect(versionText).toBe('v1.0.0');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('does not display the version number when nightly is false', () => {
|
it('does not display the version number when nightly is false', () => {
|
||||||
|
|||||||
@@ -7,17 +7,9 @@
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import { Box } from 'ink';
|
import { Box } from 'ink';
|
||||||
import { ThemedGradient } from './ThemedGradient.js';
|
import { ThemedGradient } from './ThemedGradient.js';
|
||||||
import {
|
import { shortAsciiLogo, longAsciiLogo, tinyAsciiLogo } from './AsciiArt.js';
|
||||||
shortAsciiLogo,
|
|
||||||
longAsciiLogo,
|
|
||||||
tinyAsciiLogo,
|
|
||||||
shortAsciiLogoIde,
|
|
||||||
longAsciiLogoIde,
|
|
||||||
tinyAsciiLogoIde,
|
|
||||||
} from './AsciiArt.js';
|
|
||||||
import { getAsciiArtWidth } from '../utils/textUtils.js';
|
import { getAsciiArtWidth } from '../utils/textUtils.js';
|
||||||
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
import { useTerminalSize } from '../hooks/useTerminalSize.js';
|
||||||
import { getTerminalProgram } from '../utils/terminalSetup.js';
|
|
||||||
import { useSnowfall } from '../hooks/useSnowfall.js';
|
import { useSnowfall } from '../hooks/useSnowfall.js';
|
||||||
|
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
@@ -32,7 +24,6 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
nightly,
|
nightly,
|
||||||
}) => {
|
}) => {
|
||||||
const { columns: terminalWidth } = useTerminalSize();
|
const { columns: terminalWidth } = useTerminalSize();
|
||||||
const isIde = getTerminalProgram();
|
|
||||||
let displayTitle;
|
let displayTitle;
|
||||||
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
||||||
const widthOfShortLogo = getAsciiArtWidth(shortAsciiLogo);
|
const widthOfShortLogo = getAsciiArtWidth(shortAsciiLogo);
|
||||||
@@ -40,11 +31,11 @@ export const Header: React.FC<HeaderProps> = ({
|
|||||||
if (customAsciiArt) {
|
if (customAsciiArt) {
|
||||||
displayTitle = customAsciiArt;
|
displayTitle = customAsciiArt;
|
||||||
} else if (terminalWidth >= widthOfLongLogo) {
|
} else if (terminalWidth >= widthOfLongLogo) {
|
||||||
displayTitle = isIde ? longAsciiLogoIde : longAsciiLogo;
|
displayTitle = longAsciiLogo;
|
||||||
} else if (terminalWidth >= widthOfShortLogo) {
|
} else if (terminalWidth >= widthOfShortLogo) {
|
||||||
displayTitle = isIde ? shortAsciiLogoIde : shortAsciiLogo;
|
displayTitle = shortAsciiLogo;
|
||||||
} else {
|
} else {
|
||||||
displayTitle = isIde ? tinyAsciiLogoIde : tinyAsciiLogo;
|
displayTitle = tinyAsciiLogo;
|
||||||
}
|
}
|
||||||
|
|
||||||
const artWidth = getAsciiArtWidth(displayTitle);
|
const artWidth = getAsciiArtWidth(displayTitle);
|
||||||
|
|||||||
@@ -283,6 +283,25 @@ describe('GitService', () => {
|
|||||||
expect.stringContaining('checkIsRepo failed'),
|
expect.stringContaining('checkIsRepo failed'),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should configure git environment to use local gitconfig', async () => {
|
||||||
|
hoistedMockCheckIsRepo.mockResolvedValue(false);
|
||||||
|
const service = new GitService(projectRoot, storage);
|
||||||
|
await service.setupShadowGitRepository();
|
||||||
|
|
||||||
|
expect(hoistedMockEnv).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({
|
||||||
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
||||||
|
GIT_CONFIG_SYSTEM: path.join(repoDir, '.gitconfig_system_empty'),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
const systemConfigContent = await fs.readFile(
|
||||||
|
path.join(repoDir, '.gitconfig_system_empty'),
|
||||||
|
'utf-8',
|
||||||
|
);
|
||||||
|
expect(systemConfigContent).toBe('');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createFileSnapshot', () => {
|
describe('createFileSnapshot', () => {
|
||||||
|
|||||||
@@ -51,6 +51,16 @@ export class GitService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getShadowRepoEnv(repoDir: string) {
|
||||||
|
const gitConfigPath = path.join(repoDir, '.gitconfig');
|
||||||
|
const systemConfigPath = path.join(repoDir, '.gitconfig_system_empty');
|
||||||
|
return {
|
||||||
|
// Prevent git from using the user's global git config.
|
||||||
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
||||||
|
GIT_CONFIG_SYSTEM: systemConfigPath,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a hidden git repository in the project root.
|
* Creates a hidden git repository in the project root.
|
||||||
* The Git repository is used to support checkpointing.
|
* The Git repository is used to support checkpointing.
|
||||||
@@ -67,7 +77,9 @@ export class GitService {
|
|||||||
'[user]\n name = Gemini CLI\n email = gemini-cli@google.com\n[commit]\n gpgsign = false\n';
|
'[user]\n name = Gemini CLI\n email = gemini-cli@google.com\n[commit]\n gpgsign = false\n';
|
||||||
await fs.writeFile(gitConfigPath, gitConfigContent);
|
await fs.writeFile(gitConfigPath, gitConfigContent);
|
||||||
|
|
||||||
const repo = simpleGit(repoDir);
|
const shadowRepoEnv = this.getShadowRepoEnv(repoDir);
|
||||||
|
await fs.writeFile(shadowRepoEnv.GIT_CONFIG_SYSTEM, '');
|
||||||
|
const repo = simpleGit(repoDir).env(shadowRepoEnv);
|
||||||
let isRepoDefined = false;
|
let isRepoDefined = false;
|
||||||
try {
|
try {
|
||||||
isRepoDefined = await repo.checkIsRepo(CheckRepoActions.IS_REPO_ROOT);
|
isRepoDefined = await repo.checkIsRepo(CheckRepoActions.IS_REPO_ROOT);
|
||||||
@@ -107,9 +119,7 @@ export class GitService {
|
|||||||
return simpleGit(this.projectRoot).env({
|
return simpleGit(this.projectRoot).env({
|
||||||
GIT_DIR: path.join(repoDir, '.git'),
|
GIT_DIR: path.join(repoDir, '.git'),
|
||||||
GIT_WORK_TREE: this.projectRoot,
|
GIT_WORK_TREE: this.projectRoot,
|
||||||
// Prevent git from using the user's global git config.
|
...this.getShadowRepoEnv(repoDir),
|
||||||
HOME: repoDir,
|
|
||||||
XDG_CONFIG_HOME: repoDir,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user