Skip to content

Commit

Permalink
Merge pull request #279 from slavashvets/main
Browse files Browse the repository at this point in the history
Git Worktree Support
  • Loading branch information
yamadashy authored Jan 11, 2025
2 parents 41314f6 + c7061a4 commit 070e422
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 3 deletions.
36 changes: 33 additions & 3 deletions src/core/file/fileSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ const findEmptyDirectories = async (
return emptyDirs;
};

// Check if a path is a git worktree reference file
const isGitWorktreeRef = async (gitPath: string): Promise<boolean> => {
try {
const stats = await fs.stat(gitPath);
if (!stats.isFile()) {
return false;
}

const content = await fs.readFile(gitPath, 'utf8');
return content.startsWith('gitdir:');
} catch {
return false;
}
};

// Get all file paths considering the config
export const searchFiles = async (rootDir: string, config: RepomixConfigMerged): Promise<FileSearchResult> => {
// First check directory permissions
Expand All @@ -66,9 +81,24 @@ export const searchFiles = async (rootDir: string, config: RepomixConfigMerged):
logger.trace('Ignore patterns:', ignorePatterns);
logger.trace('Ignore file patterns:', ignoreFilePatterns);

// Check if .git is a worktree reference
const gitPath = path.join(rootDir, '.git');
const isWorktree = await isGitWorktreeRef(gitPath);

// Modify ignore patterns for git worktree
const adjustedIgnorePatterns = [...ignorePatterns];
if (isWorktree) {
// Remove '.git/**' pattern and add '.git' to ignore the reference file
const gitIndex = adjustedIgnorePatterns.indexOf('.git/**');
if (gitIndex !== -1) {
adjustedIgnorePatterns.splice(gitIndex, 1);
adjustedIgnorePatterns.push('.git');
}
}

const filePaths = await globby(includePatterns, {
cwd: rootDir,
ignore: [...ignorePatterns],
ignore: [...adjustedIgnorePatterns],
ignoreFiles: [...ignoreFilePatterns],
onlyFiles: true,
absolute: false,
Expand All @@ -89,15 +119,15 @@ export const searchFiles = async (rootDir: string, config: RepomixConfigMerged):
if (config.output.includeEmptyDirectories) {
const directories = await globby(includePatterns, {
cwd: rootDir,
ignore: [...ignorePatterns],
ignore: [...adjustedIgnorePatterns],
ignoreFiles: [...ignoreFilePatterns],
onlyDirectories: true,
absolute: false,
dot: true,
followSymbolicLinks: false,
});

emptyDirPaths = await findEmptyDirectories(rootDir, directories, ignorePatterns);
emptyDirPaths = await findEmptyDirectories(rootDir, directories, adjustedIgnorePatterns);
}

logger.trace(`Filtered ${filePaths.length} files`);
Expand Down
69 changes: 69 additions & 0 deletions tests/core/file/fileSearch.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { Stats } from 'node:fs';
import * as fs from 'node:fs/promises';
import path from 'node:path';
import process from 'node:process';
Expand Down Expand Up @@ -272,5 +273,73 @@ node_modules
expect(result.filePaths).toContain('root/subdir/ignored.js');
expect(result.emptyDirPaths).toEqual([]);
});

test('should handle git worktree correctly', async () => {
// Mock .git file content for worktree
const gitWorktreeContent = 'gitdir: /path/to/main/repo/.git/worktrees/feature-branch';

// Mock fs.stat and fs.readFile for .git file
vi.mocked(fs.stat).mockResolvedValue({
isFile: () => true,
} as Stats);
vi.mocked(fs.readFile).mockResolvedValue(gitWorktreeContent);

// Mock globby to return some test files
vi.mocked(globby).mockResolvedValue(['file1.js', 'file2.js']);

const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: true,
customPatterns: [],
},
});

const result = await searchFiles('/test/dir', mockConfig);

// Check that globby was called with correct ignore patterns
const globbyCall = vi.mocked(globby).mock.calls[0];
const ignorePatterns = globbyCall[1]?.ignore as string[];

// Verify .git file (not directory) is in ignore patterns
expect(ignorePatterns).toContain('.git');
// Verify .git/** is not in ignore patterns
expect(ignorePatterns).not.toContain('.git/**');

// Verify the files were returned correctly
expect(result.filePaths).toEqual(['file1.js', 'file2.js']);
});

test('should handle regular git repository correctly', async () => {
// Mock .git as a directory
vi.mocked(fs.stat).mockResolvedValue({
isFile: () => false,
} as Stats);

// Mock globby to return some test files
vi.mocked(globby).mockResolvedValue(['file1.js', 'file2.js']);

const mockConfig = createMockConfig({
ignore: {
useGitignore: true,
useDefaultPatterns: true,
customPatterns: [],
},
});

const result = await searchFiles('/test/dir', mockConfig);

// Check that globby was called with correct ignore patterns
const globbyCall = vi.mocked(globby).mock.calls[0];
const ignorePatterns = globbyCall[1]?.ignore as string[];

// Verify .git/** is in ignore patterns for regular git repos
expect(ignorePatterns).toContain('.git/**');
// Verify just .git is not in ignore patterns
expect(ignorePatterns).not.toContain('.git');

// Verify the files were returned correctly
expect(result.filePaths).toEqual(['file1.js', 'file2.js']);
});
});
});

0 comments on commit 070e422

Please sign in to comment.