feat: represent symlink diffs as link targets
Untracked symlinks now show as link entries in diff output. File diffs display symlink targets instead of following them. Added tests for patch and split diff behavior.
This commit is contained in:
@@ -493,7 +493,9 @@ const resolveGitFileContext = async (directoryPath, git, filePath, repoRootOverr
|
||||
}
|
||||
|
||||
const repoPath = toGitPath(path.relative(repoRoot, absolutePath));
|
||||
const existsInWorktree = await fsp.stat(absolutePath).then((stat) => stat.isFile()).catch(() => false);
|
||||
const worktreeEntry = await fsp.lstat(absolutePath).catch(() => null);
|
||||
const isSymbolicLink = worktreeEntry?.isSymbolicLink() ?? false;
|
||||
const existsInWorktree = worktreeEntry?.isFile() || isSymbolicLink;
|
||||
const existsInIndex = await git.raw(['cat-file', '-e', `:${repoPath}`]).then(() => true).catch(() => false);
|
||||
const existsInHead = await git.raw(['cat-file', '-e', `HEAD:${repoPath}`]).then(() => true).catch(() => false);
|
||||
|
||||
@@ -502,6 +504,7 @@ const resolveGitFileContext = async (directoryPath, git, filePath, repoRootOverr
|
||||
absolutePath,
|
||||
repoPath,
|
||||
repoRoot,
|
||||
isSymbolicLink,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2358,6 +2361,20 @@ export async function getDiff(directory, { path: filePath, staged = false, conte
|
||||
await git.raw(['ls-files', '--error-unmatch', '--', fileContext.repoPath]);
|
||||
return diff;
|
||||
} catch {
|
||||
if (fileContext.isSymbolicLink) {
|
||||
const target = await fsp.readlink(fileContext.absolutePath);
|
||||
return [
|
||||
`diff --git a/${fileContext.repoPath} b/${fileContext.repoPath}`,
|
||||
'new file mode 120000',
|
||||
'--- /dev/null',
|
||||
`+++ b/${fileContext.repoPath}`,
|
||||
'@@ -0,0 +1 @@',
|
||||
`+${target}`,
|
||||
'\\ No newline at end of file',
|
||||
'',
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
const noIndexArgs = ['diff', '--no-color'];
|
||||
if (typeof contextLines === 'number' && !Number.isNaN(contextLines)) {
|
||||
noIndexArgs.push(`-U${Math.max(0, contextLines)}`);
|
||||
@@ -2555,9 +2572,9 @@ export async function getFileDiff(directory, { path: filePath, staged = false }
|
||||
const { directoryPath, directoryGit, repoRoot, git } = await createRepositoryGitContext(directory);
|
||||
const isImage = isImageFile(filePath);
|
||||
const mimeType = isImage ? getImageMimeType(filePath) : null;
|
||||
const { absolutePath, repoPath } = await resolveGitFileContext(directoryPath, directoryGit, filePath, repoRoot);
|
||||
const { absolutePath, repoPath, isSymbolicLink } = await resolveGitFileContext(directoryPath, directoryGit, filePath, repoRoot);
|
||||
|
||||
if (!isImage) {
|
||||
if (!isImage && !isSymbolicLink) {
|
||||
const isBinaryBySniff = await looksBinaryBySniff(absolutePath);
|
||||
const isBinary = isBinaryBySniff || (await isBinaryDiff(repoRoot, repoPath, staged));
|
||||
if (isBinary) {
|
||||
@@ -2611,8 +2628,18 @@ export async function getFileDiff(directory, { path: filePath, staged = false }
|
||||
modified = await git.show([`:${repoPath}`]);
|
||||
}
|
||||
} else {
|
||||
const stat = await fsp.stat(absolutePath);
|
||||
if (stat.isFile()) {
|
||||
if (isSymbolicLink) {
|
||||
modified = await fsp.readlink(absolutePath);
|
||||
} else {
|
||||
const stat = await fsp.stat(absolutePath);
|
||||
if (!stat.isFile()) {
|
||||
return {
|
||||
original: typeof original === 'string' ? original.replace(/\r\n/g, '\n') : original,
|
||||
modified: '',
|
||||
path: filePath,
|
||||
isBinary: false,
|
||||
};
|
||||
}
|
||||
if (isImage) {
|
||||
// For images, read as binary and convert to data URL
|
||||
const buffer = await fsp.readFile(absolutePath);
|
||||
|
||||
Reference in New Issue
Block a user