Skip to content

Commit 35bb994

Browse files
authored
fix(vcs): prefer nearest detected repository (#342)
1 parent 02c4a4a commit 35bb994

4 files changed

Lines changed: 41 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ All notable user-visible changes to Hunk are documented in this file.
1212

1313
### Fixed
1414

15+
- Fixed VCS auto-detection so a Git repository nested under a parent Jujutsu workspace still uses Git mode by default.
16+
1517
## [0.13.1] - 2026-05-19
1618

1719
### Fixed

src/core/config.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,16 @@ describe("config resolution", () => {
246246
const jjRepo = createTempDir("hunk-config-jj-repo-");
247247
const colocatedRepo = createTempDir("hunk-config-colocated-repo-");
248248
const gitRepo = createTempDir("hunk-config-git-repo-");
249+
const parentJjRepo = createTempDir("hunk-config-parent-jj-");
250+
const gitRepoInsideParentJj = join(parentJjRepo, "git-project");
249251
const plainDir = createTempDir("hunk-config-no-repo-");
250252

251253
createJjRepo(jjRepo);
252254
createRepo(colocatedRepo);
253255
createJjRepo(colocatedRepo);
254256
createRepo(gitRepo);
257+
createJjRepo(parentJjRepo);
258+
createRepo(gitRepoInsideParentJj);
255259

256260
const input = {
257261
kind: "vcs",
@@ -269,6 +273,10 @@ describe("config resolution", () => {
269273
expect(
270274
resolveConfiguredCliInput(input, { cwd: gitRepo, env: { HOME: home } }).input.options.vcs,
271275
).toBe("git");
276+
expect(
277+
resolveConfiguredCliInput(input, { cwd: gitRepoInsideParentJj, env: { HOME: home } }).input
278+
.options.vcs,
279+
).toBe("git");
272280
expect(
273281
resolveConfiguredCliInput(input, { cwd: plainDir, env: { HOME: home } }).input.options.vcs,
274282
).toBe("git");

src/core/vcs/index.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ describe("VCS adapter registry", () => {
8181
expect(findVcsRepoRootCandidate(nested)).toBe(repo);
8282
});
8383

84+
test("prefers the nearest checkout over a parent repository with higher adapter priority", () => {
85+
const parent = createTempDir("hunk-vcs-parent-jj-");
86+
const repo = join(parent, "project");
87+
const nested = join(repo, "src", "nested");
88+
mkdirSync(join(parent, ".jj"));
89+
mkdirSync(join(repo, ".git"), { recursive: true });
90+
mkdirSync(nested, { recursive: true });
91+
92+
expect(detectVcs(nested)).toEqual({ id: "git", repoRoot: repo });
93+
expect(findVcsRepoRootCandidate(nested)).toBe(repo);
94+
});
95+
8496
test("maps CLI inputs to neutral review operations", () => {
8597
const diffInput = {
8698
kind: "vcs",

src/core/vcs/index.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dirname, resolve } from "node:path";
1+
import { dirname, relative, resolve } from "node:path";
22
import { HunkUserError } from "../errors";
33
import { gitAdapter } from "./git";
44
import { jjAdapter } from "./jj";
@@ -18,14 +18,28 @@ export function isVcsId(value: unknown): value is VcsId {
1818
return vcsAdapters.some((adapter) => adapter.id === value);
1919
}
2020

21+
/** Detect the nearest containing VCS checkout, using adapter order only to break same-root ties. */
2122
export function detectVcs(cwd: string): VcsDetection | null {
23+
const start = resolve(cwd);
24+
let bestDetection: VcsDetection | null = null;
25+
let bestDistance = Number.POSITIVE_INFINITY;
26+
2227
for (const adapter of vcsAdapters) {
23-
const detected = adapter.detect(cwd);
24-
if (detected) {
25-
return detected;
28+
const detected = adapter.detect(start);
29+
if (!detected) {
30+
continue;
31+
}
32+
33+
const distance = relative(detected.repoRoot, start)
34+
.split(/[\\/]+/)
35+
.filter(Boolean).length;
36+
if (distance < bestDistance) {
37+
bestDetection = detected;
38+
bestDistance = distance;
2639
}
2740
}
28-
return null;
41+
42+
return bestDetection;
2943
}
3044

3145
export function findVcsRepoRootCandidate(cwd = process.cwd()) {

0 commit comments

Comments
 (0)