Skip to content

Commit 79f24f4

Browse files
committed
fix: add support for git worktree
fixes #87
1 parent 37c134e commit 79f24f4

File tree

7 files changed

+37
-43
lines changed

7 files changed

+37
-43
lines changed

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
"@softwareventures/array": "7.0.0",
3131
"@softwareventures/nullable": "3.2.0",
3232
"execa": "5.1.1",
33-
"find-up": "5.0.0",
3433
"glob": "10.3.10",
3534
"ignore": "5.3.1",
3635
"mri": "1.2.0",

src/git-utils.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
1-
import {dirname} from "path";
1+
import {normalize} from "path";
22
import {hasProperty} from "unknown";
33
import {notNull} from "@softwareventures/nullable";
4-
import findUp = require("find-up");
54
import {runCommand} from "./utils";
65

76
interface DiffIndexFile {
87
diffFilterChar: string;
98
filename: string;
109
}
1110

12-
export async function resolveNearestGitDirectoryParent(workingDirectory: string): Promise<string> {
13-
const gitDirectoryPath = await findUp(".git", {cwd: workingDirectory, type: "directory"});
14-
if (gitDirectoryPath == null) {
15-
throw new Error("No .git directory found");
16-
}
17-
return dirname(gitDirectoryPath);
11+
export async function resolveGitWorkingTreePath(workingDirectory: string): Promise<string> {
12+
return runCommand("git", ["rev-parse", "--show-toplevel"], workingDirectory)
13+
.then(({stdout}) => stdout)
14+
.then(normalize);
1815
}
1916

2017
export const index = Symbol("index");

src/index.ts

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,7 @@ import {
1414
of,
1515
scan
1616
} from "rxjs";
17-
import {
18-
getModifiedFilenames,
19-
index,
20-
resolveNearestGitDirectoryParent,
21-
workingTree
22-
} from "./git-utils";
17+
import {getModifiedFilenames, index, resolveGitWorkingTreePath, workingTree} from "./git-utils";
2318
import {generateFilesWhitelistPredicate, noLineChangeDataError} from "./utils";
2419
import {preciseFormatterPrettier} from "./precise-formatters/prettier";
2520
import {ModifiedFile} from "./modified-file";
@@ -81,19 +76,19 @@ export function main(
8176

8277
const selectedFormatter = await preciseFormatterPrettier();
8378

84-
// Resolve the relevant .git directory's parent directory up front, as we will need this when
85-
// executing various `git` commands.
86-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(workingDirectory);
79+
// Resolve the working tree path up front, as we will need this
80+
// when executing various `git` commands.
81+
const workingTreePath = await resolveGitWorkingTreePath(workingDirectory);
8782

8883
// Find files that we should process. A file is relevant if:
8984
// * The file extension is supported by the given formatter.
9085
// * The file is included in the optional `filesWhitelist` array, or no whitelist is specified.
9186
// * The file is not ignored as a result of any supported "ignore" mechanism of the formatter.
9287
const relevantFiles = from(
93-
getModifiedFilenames(gitDirectoryParent, options.base, options.head)
88+
getModifiedFilenames(workingTreePath, options.base, options.head)
9489
).pipe(
9590
mergeMap(array => array),
96-
map(path => join(gitDirectoryParent, path)),
91+
map(path => join(workingTreePath, path)),
9792
map(path => relative(workingDirectory, path)),
9893
filter(path => !isAbsolute(path)),
9994
filter(selectedFormatter.hasSupportedFileExtension),
@@ -117,7 +112,7 @@ export function main(
117112
// Read the modified file contents and resolve the relevant formatter.
118113
const modifiedFile = await ModifiedFile.read({
119114
fullPath,
120-
gitDirectoryParent,
115+
gitDirectoryParent: workingTreePath,
121116
base: options.base,
122117
head: options.head ?? index,
123118
selectedFormatter
@@ -181,7 +176,7 @@ export function main(
181176
if (options.head == null) {
182177
const workingTreeFile = await ModifiedFile.read({
183178
fullPath,
184-
gitDirectoryParent,
179+
gitDirectoryParent: workingTreePath,
185180
base: options.base,
186181
head: workingTree,
187182
selectedFormatter

test/git-utils.spec.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
import {sep} from "path";
2+
import * as tempy from "tempy";
3+
import {mkdirp} from "mkdirp";
4+
import {runCommand} from "@softwareventures/precise-commits/lib/utils";
15
import {
26
getDiffForFile,
3-
resolveNearestGitDirectoryParent,
7+
resolveGitWorkingTreePath,
48
getModifiedFilenames,
59
index
610
} from "../src/git-utils";
@@ -10,7 +14,7 @@ const fixtures = readFixtures();
1014
let testBed: TestBed;
1115

1216
describe("git-utils", () => {
13-
describe("resolveNearestGitDirectoryParent()", () => {
17+
describe("resolveGitWorkingTreePath()", () => {
1418
beforeAll(() => {
1519
testBed = new TestBed();
1620
});
@@ -26,11 +30,21 @@ describe("git-utils", () => {
2630
/**
2731
* The tmpFile should resolve to its own .git directory
2832
*/
29-
expect(await resolveNearestGitDirectoryParent(tmpFile.directoryPath)).toEqual(
33+
expect(await resolveGitWorkingTreePath(tmpFile.directoryPath)).toEqual(
3034
tmpFile.directoryPath
3135
);
3236
});
3337
});
38+
39+
it(`should resolve the correct working tree path in a working tree created by git worktree`, async () => {
40+
await tempy.directory.task(async worktreePath => {
41+
await runCommand("git", ["worktree", "add", "-B", "worktree", worktreePath]);
42+
const subdirPath = `${worktreePath}${sep}subdir`;
43+
await mkdirp(subdirPath);
44+
expect(await resolveGitWorkingTreePath(subdirPath)).toEqual(worktreePath);
45+
await runCommand("git", ["worktree", "remove", worktreePath]);
46+
});
47+
});
3448
});
3549

3650
describe("getDiffForFile()", () => {
@@ -46,9 +60,7 @@ describe("git-utils", () => {
4660
it(fixture.fixtureName, async () => {
4761
await testBed.prepareFixtureInTmpDirectory(fixture);
4862
const tmpFile = testBed.getTmpFileForFixture(fixture);
49-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(
50-
tmpFile.directoryPath
51-
);
63+
const gitDirectoryParent = await resolveGitWorkingTreePath(tmpFile.directoryPath);
5264
const diff = await getDiffForFile(
5365
gitDirectoryParent,
5466
tmpFile.path,
@@ -73,9 +85,7 @@ describe("git-utils", () => {
7385
it(fixture.fixtureName, async () => {
7486
await testBed.prepareFixtureInTmpDirectory(fixture);
7587
const tmpFile = testBed.getTmpFileForFixture(fixture);
76-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(
77-
tmpFile.directoryPath
78-
);
88+
const gitDirectoryParent = await resolveGitWorkingTreePath(tmpFile.directoryPath);
7989
const fileNames = await getModifiedFilenames(
8090
gitDirectoryParent,
8191
tmpFile.initialCommitSHA,

test/modified-file.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {ModifiedFile} from "../src/modified-file";
22
import {preciseFormatterPrettier} from "../src/precise-formatters/prettier";
3-
import {resolveNearestGitDirectoryParent, workingTree} from "../src/git-utils";
3+
import {resolveGitWorkingTreePath, workingTree} from "../src/git-utils";
44
import {TestBed, readFixtures} from "./test-utils";
55

66
const fixtures = readFixtures();
@@ -20,9 +20,7 @@ describe("ModifiedFile", () => {
2020
it(fixture.fixtureName, async () => {
2121
await testBed.prepareFixtureInTmpDirectory(fixture);
2222
const tmpFile = testBed.getTmpFileForFixture(fixture);
23-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(
24-
tmpFile.directoryPath
25-
);
23+
const gitDirectoryParent = await resolveGitWorkingTreePath(tmpFile.directoryPath);
2624
const selectedFormatter = await preciseFormatterPrettier();
2725
const modifiedFile = await ModifiedFile.read({
2826
fullPath: tmpFile.path,

test/utils.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {getDiffForFile, index, resolveNearestGitDirectoryParent} from "../src/git-utils";
1+
import {getDiffForFile, index, resolveGitWorkingTreePath} from "../src/git-utils";
22
import {extractLineChangeData, calculateCharacterRangesFromLineChanges} from "../src/utils";
33
import {TestBed, readFixtures} from "./test-utils";
44

@@ -39,9 +39,7 @@ describe("utils", () => {
3939
it(fixture.fixtureName, async () => {
4040
await testBed.prepareFixtureInTmpDirectory(fixture);
4141
const tmpFile = testBed.getTmpFileForFixture(fixture);
42-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(
43-
tmpFile.directoryPath
44-
);
42+
const gitDirectoryParent = await resolveGitWorkingTreePath(tmpFile.directoryPath);
4543
const diff = await getDiffForFile(
4644
gitDirectoryParent,
4745
tmpFile.path,
@@ -67,9 +65,7 @@ describe("utils", () => {
6765
it(fixture.fixtureName, async () => {
6866
await testBed.prepareFixtureInTmpDirectory(fixture);
6967
const tmpFile = testBed.getTmpFileForFixture(fixture);
70-
const gitDirectoryParent = await resolveNearestGitDirectoryParent(
71-
tmpFile.directoryPath
72-
);
68+
const gitDirectoryParent = await resolveGitWorkingTreePath(tmpFile.directoryPath);
7369
const diff = await getDiffForFile(
7470
gitDirectoryParent,
7571
tmpFile.path,

yarn.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1719,7 +1719,6 @@ __metadata:
17191719
eslint-plugin-prefer-arrow: "npm:1.2.3"
17201720
eslint-plugin-sonarjs: "npm:0.25.1"
17211721
execa: "npm:5.1.1"
1722-
find-up: "npm:5.0.0"
17231722
glob: "npm:10.3.10"
17241723
husky: "npm:9.0.11"
17251724
ignore: "npm:5.3.1"

0 commit comments

Comments
 (0)