Unverified 提交 daf69251 authored 作者: Will Chen's avatar Will Chen 提交者: GitHub

Automatically initialize git safe directory on startup (#2152)

See https://github.com/dyad-sh/dyad/issues/2113 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Automatically ensures Git can operate in `dyad-apps` when native Git is enabled and centralizes base path resolution. > > - Adds `gitAddSafeDirectory(directory)` in `git_utils.ts` to idempotently append to global `safe.directory` (uses `normalizePath`, logs outcomes) > - On startup (`main.ts`), calls `gitAddSafeDirectory(getDyadAppsBaseDirectory())` without awaiting > - Introduces `getDyadAppsBaseDirectory()` and updates `getDyadAppPath()` to use it, consolidating test/prod path logic > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 99911c273fba66190218ecdb1df40d61f12d49a5. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Automatically add the dyad-apps directory to Git’s global safe.directory at startup when native Git is enabled. This prevents “detected dubious ownership” errors on Windows and unblocks Git operations. - New Features - Added gitAddSafeDirectory(directory) to run git config --global --add safe.directory <dir> with logging, normalizing paths and skipping duplicates. - On app ready, if settings.enableNativeGit, call gitAddSafeDirectory(getDyadAppsBaseDirectory()) without awaiting to keep startup fast. - Refactors - Introduced getDyadAppsBaseDirectory() and updated getDyadAppPath() to use it, centralizing base path logic for test and prod. <sup>Written for commit 99911c273fba66190218ecdb1df40d61f12d49a5. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. -->
上级 7749a5d6
...@@ -7,6 +7,7 @@ import { promises as fsPromises } from "node:fs"; ...@@ -7,6 +7,7 @@ import { promises as fsPromises } from "node:fs";
import pathModule from "node:path"; import pathModule from "node:path";
import { readSettings } from "../../main/settings"; import { readSettings } from "../../main/settings";
import log from "electron-log"; import log from "electron-log";
import { normalizePath } from "../../../shared/normalizePath";
const logger = log.scope("git_utils"); const logger = log.scope("git_utils");
import type { import type {
GitBaseParams, GitBaseParams,
...@@ -63,6 +64,53 @@ export async function withGitAuthor(args: string[]): Promise<string[]> { ...@@ -63,6 +64,53 @@ export async function withGitAuthor(args: string[]): Promise<string[]> {
]; ];
} }
/**
* Adds a directory to git's global safe.directory list.
* This is required on Windows when git operations are performed on directories
* owned by different users.
* Only works for native git.
*/
export async function gitAddSafeDirectory(directory: string): Promise<void> {
// Normalize path to use forward slashes (important for Windows compatibility with git)
directory = normalizePath(directory);
try {
// First check if the directory is already in the safe.directory list
const checkResult = await exec(
["config", "--global", "--get-all", "safe.directory"],
".",
);
// Parse existing safe directories (one per line), normalizing for comparison
const existingSafeDirectories = checkResult.stdout
.split("\n")
.map((line) => normalizePath(line.trim()))
.filter((line) => line.length > 0);
// Check if already present (exact match after normalization)
if (existingSafeDirectories.includes(directory)) {
logger.debug(`Safe directory already exists: ${directory}`);
return;
}
const result = await exec(
["config", "--global", "--add", "safe.directory", directory],
".",
);
if (result.exitCode !== 0) {
logger.warn(
`Failed to add safe directory '${directory}': ${result.stderr.trim() || result.stdout.trim()}`,
);
} else {
logger.info(`Added safe directory: ${directory}`);
}
} catch (error: any) {
logger.warn(
`Failed to add safe directory '${directory}': ${error.message}`,
);
}
}
export async function getCurrentCommitHash({ export async function getCurrentCommitHash({
path, path,
ref = "HEAD", ref = "HEAD",
......
...@@ -30,6 +30,8 @@ import { ...@@ -30,6 +30,8 @@ import {
} from "./utils/performance_monitor"; } from "./utils/performance_monitor";
import { cleanupOldAiMessagesJson } from "./pro/main/ipc/handlers/local_agent/ai_messages_cleanup"; import { cleanupOldAiMessagesJson } from "./pro/main/ipc/handlers/local_agent/ai_messages_cleanup";
import fs from "fs"; import fs from "fs";
import { gitAddSafeDirectory } from "./ipc/utils/git_utils";
import { getDyadAppsBaseDirectory } from "./paths/paths";
log.errorHandler.startCatching(); log.errorHandler.startCatching();
log.eventLogger.startLogging(); log.eventLogger.startLogging();
...@@ -92,6 +94,13 @@ export async function onReady() { ...@@ -92,6 +94,13 @@ export async function onReady() {
const settings = readSettings(); const settings = readSettings();
// Add dyad-apps directory to git safe.directory (required for Windows)
if (settings.enableNativeGit) {
// Don't need to await because this only needs to run before
// the user starts interacting with Dyad app and uses a git-related feature.
gitAddSafeDirectory(getDyadAppsBaseDirectory());
}
// Check if app was force-closed // Check if app was force-closed
if (settings.isRunning) { if (settings.isRunning) {
logger.warn("App was force-closed on previous run"); logger.warn("App was force-closed on previous run");
......
...@@ -2,17 +2,24 @@ import path from "node:path"; ...@@ -2,17 +2,24 @@ import path from "node:path";
import os from "node:os"; import os from "node:os";
import { IS_TEST_BUILD } from "../ipc/utils/test_utils"; import { IS_TEST_BUILD } from "../ipc/utils/test_utils";
/**
* Gets the base dyad-apps directory path (without a specific app subdirectory)
*/
export function getDyadAppsBaseDirectory(): string {
if (IS_TEST_BUILD) {
const electron = getElectron();
return path.join(electron!.app.getPath("userData"), "dyad-apps");
}
return path.join(os.homedir(), "dyad-apps");
}
export function getDyadAppPath(appPath: string): string { export function getDyadAppPath(appPath: string): string {
// If appPath is already absolute, use it as-is // If appPath is already absolute, use it as-is
if (path.isAbsolute(appPath)) { if (path.isAbsolute(appPath)) {
return appPath; return appPath;
} }
// Otherwise, use the default base path // Otherwise, use the default base path
if (IS_TEST_BUILD) { return path.join(getDyadAppsBaseDirectory(), appPath);
const electron = getElectron();
return path.join(electron!.app.getPath("userData"), "dyad-apps", appPath);
}
return path.join(os.homedir(), "dyad-apps", appPath);
} }
export function getTypeScriptCachePath(): string { export function getTypeScriptCachePath(): string {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论