mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
feat: enhance git diff functionality for untracked files
- Implemented synthetic diff generation for untracked files in both git and non-git directories. - Added fallback UI in the GitDiffPanel for files without diff content, ensuring better user experience. - Improved error handling and logging for git operations, enhancing reliability in file diff retrieval. This update allows users to see diffs for new files that are not yet tracked by git, improving the overall functionality of the diff panel.
This commit is contained in:
@@ -8,9 +8,22 @@ import { promisify } from "util";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { getErrorMessage, logError } from "../common.js";
|
||||
import { appendUntrackedFileDiffs, generateDiffsForNonGitDirectory } from "../../common.js";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
/**
|
||||
* Check if a path is a git repository
|
||||
*/
|
||||
async function isGitRepo(repoPath: string): Promise<boolean> {
|
||||
try {
|
||||
await execAsync("git rev-parse --is-inside-work-tree", { cwd: repoPath });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function createDiffsHandler() {
|
||||
return async (req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
@@ -38,6 +51,22 @@ export function createDiffsHandler() {
|
||||
|
||||
try {
|
||||
await fs.access(worktreePath);
|
||||
|
||||
// Check if worktree is a git repository
|
||||
const isRepo = await isGitRepo(worktreePath);
|
||||
|
||||
if (!isRepo) {
|
||||
// Not a git repo - list all files and treat them as new
|
||||
const result = await generateDiffsForNonGitDirectory(worktreePath);
|
||||
res.json({
|
||||
success: true,
|
||||
diff: result.diff,
|
||||
files: result.files,
|
||||
hasChanges: result.files.length > 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const { stdout: diff } = await execAsync("git diff HEAD", {
|
||||
cwd: worktreePath,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
@@ -68,14 +97,79 @@ export function createDiffsHandler() {
|
||||
};
|
||||
});
|
||||
|
||||
// Generate synthetic diffs for untracked (new) files
|
||||
// git diff HEAD doesn't include untracked files, so we need to generate them
|
||||
const combinedDiff = await appendUntrackedFileDiffs(worktreePath, diff, files);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
diff,
|
||||
diff: combinedDiff,
|
||||
files,
|
||||
hasChanges: files.length > 0,
|
||||
});
|
||||
} catch {
|
||||
res.json({ success: true, diff: "", files: [], hasChanges: false });
|
||||
} catch (innerError) {
|
||||
// Worktree doesn't exist - fallback to main project path
|
||||
logError(innerError, "Worktree access failed, falling back to main project");
|
||||
|
||||
try {
|
||||
// Check if main project is a git repo
|
||||
const isRepo = await isGitRepo(projectPath);
|
||||
|
||||
if (!isRepo) {
|
||||
// Not a git repo - list all files and treat them as new
|
||||
const result = await generateDiffsForNonGitDirectory(projectPath);
|
||||
res.json({
|
||||
success: true,
|
||||
diff: result.diff,
|
||||
files: result.files,
|
||||
hasChanges: result.files.length > 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Try main project path for git diffs
|
||||
const { stdout: diff } = await execAsync("git diff HEAD", {
|
||||
cwd: projectPath,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
});
|
||||
const { stdout: status } = await execAsync("git status --porcelain", {
|
||||
cwd: projectPath,
|
||||
});
|
||||
|
||||
const files = status
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.map((line) => {
|
||||
const statusChar = line[0];
|
||||
const filePath = line.slice(3);
|
||||
const statusMap: Record<string, string> = {
|
||||
M: "Modified",
|
||||
A: "Added",
|
||||
D: "Deleted",
|
||||
R: "Renamed",
|
||||
C: "Copied",
|
||||
U: "Updated",
|
||||
"?": "Untracked",
|
||||
};
|
||||
return {
|
||||
status: statusChar,
|
||||
path: filePath,
|
||||
statusText: statusMap[statusChar] || "Unknown",
|
||||
};
|
||||
});
|
||||
|
||||
const combinedDiff = await appendUntrackedFileDiffs(projectPath, diff, files);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
diff: combinedDiff,
|
||||
files,
|
||||
hasChanges: files.length > 0,
|
||||
});
|
||||
} catch (fallbackError) {
|
||||
logError(fallbackError, "Fallback to main project also failed");
|
||||
res.json({ success: true, diff: "", files: [], hasChanges: false });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logError(error, "Get worktree diffs failed");
|
||||
|
||||
@@ -8,6 +8,7 @@ import { promisify } from "util";
|
||||
import path from "path";
|
||||
import fs from "fs/promises";
|
||||
import { getErrorMessage, logError } from "../common.js";
|
||||
import { generateSyntheticDiffForNewFile } from "../../common.js";
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -37,16 +38,34 @@ export function createFileDiffHandler() {
|
||||
|
||||
try {
|
||||
await fs.access(worktreePath);
|
||||
const { stdout: diff } = await execAsync(
|
||||
`git diff HEAD -- "${filePath}"`,
|
||||
{
|
||||
cwd: worktreePath,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
}
|
||||
|
||||
// First check if the file is untracked
|
||||
const { stdout: status } = await execAsync(
|
||||
`git status --porcelain -- "${filePath}"`,
|
||||
{ cwd: worktreePath }
|
||||
);
|
||||
|
||||
const isUntracked = status.trim().startsWith("??");
|
||||
|
||||
let diff: string;
|
||||
if (isUntracked) {
|
||||
// Generate synthetic diff for untracked file
|
||||
diff = await generateSyntheticDiffForNewFile(worktreePath, filePath);
|
||||
} else {
|
||||
// Use regular git diff for tracked files
|
||||
const result = await execAsync(
|
||||
`git diff HEAD -- "${filePath}"`,
|
||||
{
|
||||
cwd: worktreePath,
|
||||
maxBuffer: 10 * 1024 * 1024,
|
||||
}
|
||||
);
|
||||
diff = result.stdout;
|
||||
}
|
||||
|
||||
res.json({ success: true, diff, filePath });
|
||||
} catch {
|
||||
} catch (innerError) {
|
||||
logError(innerError, "Worktree file diff failed");
|
||||
res.json({ success: true, diff: "", filePath });
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user