Skip to content

Commit ed9c7f6

Browse files
authored
Fix --mount-git-worktree-common-dir has no effect when the devcontainer.json defines a custom workspaceMount
1 parent 65f98a5 commit ed9c7f6

2 files changed

Lines changed: 67 additions & 7 deletions

File tree

src/spec-node/utils.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -383,11 +383,20 @@ export async function getWorkspaceConfiguration(cliHost: CLIHost, workspace: Wor
383383
}
384384
let { workspaceFolder, workspaceMount } = config;
385385
let additionalMountString: string | undefined;
386-
if (workspace && (!workspaceFolder || !('workspaceMount' in config))) {
386+
if (workspace && (!workspaceFolder || !('workspaceMount' in config) || (mountWorkspaceGitRoot && mountGitWorktreeCommonDir))) {
387387
const hostMountFolder = await getHostMountFolder(cliHost, workspace.rootFolderPath, mountWorkspaceGitRoot, output);
388388

389+
// When the user provides a custom workspaceMount, derive containerMountFolder from its
390+
// target= value so that the worktree common-dir path is computed correctly.
391+
let containerMountFolder: string;
392+
if ('workspaceMount' in config && config.workspaceMount) {
393+
const targetMatch = /(?:^|,)(?:dst|destination|target)=(?:"([^"]+)"|([^,]+))/.exec(config.workspaceMount);
394+
containerMountFolder = targetMatch ? (targetMatch[1] ?? targetMatch[2]) : path.posix.join('/workspaces', cliHost.path.basename(hostMountFolder));
395+
} else {
396+
containerMountFolder = path.posix.join('/workspaces', cliHost.path.basename(hostMountFolder));
397+
}
398+
389399
// Check if .git is a file (worktree) with a relative gitdir path
390-
let containerMountFolder = path.posix.join('/workspaces', cliHost.path.basename(hostMountFolder));
391400
if (mountWorkspaceGitRoot && mountGitWorktreeCommonDir) {
392401
const dotGitPath = cliHost.path.join(hostMountFolder, '.git');
393402
if (await cliHost.isFile(dotGitPath)) {
@@ -399,12 +408,16 @@ export async function getWorkspaceConfiguration(cliHost: CLIHost, workspace: Wor
399408
if (!cliHost.path.isAbsolute(gitdir)) {
400409
// gitdir points to .git/worktrees/<name>/, common dir is .git/ (two levels up)
401410
const gitCommonDir = cliHost.path.resolve(hostMountFolder, gitdir, '..', '..');
402-
// Collect path segments from hostMountFolder up to the parent of gitCommonDir
403-
const segments: string[] = [];
404-
for (let current = hostMountFolder; !gitCommonDir.startsWith(current + cliHost.path.sep) && current !== cliHost.path.dirname(current); current = cliHost.path.dirname(current)) {
405-
segments.unshift(cliHost.path.basename(current));
411+
// Only recompute containerMountFolder when the workspace mount is auto-generated;
412+
// when the user supplied workspaceMount, keep the target they specified.
413+
if (!('workspaceMount' in config)) {
414+
// Collect path segments from hostMountFolder up to the parent of gitCommonDir
415+
const segments: string[] = [];
416+
for (let current = hostMountFolder; !gitCommonDir.startsWith(current + cliHost.path.sep) && current !== cliHost.path.dirname(current); current = cliHost.path.dirname(current)) {
417+
segments.unshift(cliHost.path.basename(current));
418+
}
419+
containerMountFolder = path.posix.join('/workspaces', ...segments);
406420
}
407-
containerMountFolder = path.posix.join('/workspaces', ...segments);
408421
// Calculate where the common dir should be mounted in the container
409422
const containerGitdir = cliHost.platform === 'win32' ? gitdir.replace(/\\/g, '/') : gitdir;
410423
const containerGitCommonDir = path.posix.resolve(containerMountFolder, containerGitdir, '..', '..');

src/test/workspaceConfiguration.test.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,53 @@ describe('getWorkspaceConfiguration', function () {
328328
assert.strictEqual(result.additionalMountString, `type=bind,source=${p.repoGitPath},target=/workspaces/repos/main/.git${p.consistency}`);
329329
});
330330

331+
it('should preserve custom workspaceMount target when adding worktree common dir mount', async () => {
332+
const p = {
333+
linux: {
334+
worktreePath: '/home/user/worktrees/feature',
335+
gitFile: '/home/user/worktrees/feature/.git',
336+
gitdir: 'gitdir: ../../repo/.git/worktrees/feature',
337+
repoGitPath: '/home/user/repo/.git',
338+
consistency: ''
339+
},
340+
darwin: {
341+
worktreePath: '/Users/user/worktrees/feature',
342+
gitFile: '/Users/user/worktrees/feature/.git',
343+
gitdir: 'gitdir: ../../repo/.git/worktrees/feature',
344+
repoGitPath: '/Users/user/repo/.git',
345+
consistency: ',consistency=consistent'
346+
},
347+
win32: {
348+
worktreePath: 'C:\\Users\\user\\worktrees\\feature',
349+
gitFile: 'C:\\Users\\user\\worktrees\\feature\\.git',
350+
gitdir: 'gitdir: ../../repo/.git/worktrees/feature',
351+
repoGitPath: 'C:\\Users\\user\\repo\\.git',
352+
consistency: ',consistency=consistent'
353+
},
354+
}[platform];
355+
356+
const cliHost = createMockCLIHost({
357+
platform,
358+
files: {
359+
[p.gitFile]: p.gitdir
360+
}
361+
});
362+
const workspace = createWorkspace(p.worktreePath);
363+
364+
const result = await getWorkspaceConfiguration(
365+
cliHost,
366+
workspace,
367+
{ workspaceMount: 'type=bind,source=${localWorkspaceFolder},target=/testworkspace' },
368+
true,
369+
true,
370+
nullLog
371+
);
372+
373+
assert.strictEqual(result.workspaceFolder, '/testworkspace');
374+
assert.strictEqual(result.workspaceMount, 'type=bind,source=${localWorkspaceFolder},target=/testworkspace');
375+
assert.strictEqual(result.additionalMountString, `type=bind,source=${p.repoGitPath},target=/repo/.git${p.consistency}`);
376+
});
377+
331378
});
332379

333380
describe('git root in parent folder', function () {

0 commit comments

Comments
 (0)