Skip to content

--mount-git-worktree-common-dir silently ignored when devcontainer.json sets a custom workspaceMount #1243

Open

Description

@AvishayHirsh

Summary

--mount-git-worktree-common-dir (added in #1127) has no effect when the devcontainer.json defines a custom workspaceMount. The worktree common-dir bind mount is never added, so in-container git fails with fatal: not a git repository for any git worktree whose devcontainer uses a custom workspaceMount.

Root cause

In src/spec-node/utils.ts (getWorkspaceConfiguration, ~L386) the entire worktree detection + common-dir mount block is guarded by:

if (workspace && (!workspaceFolder || !('workspaceMount' in config))) { ... }

When workspaceMount is present, the block is skipped — the .git file is never read, the common dir is never resolved, and no mount is added. (Flagged as a possible oversight by Jérémy Lal (@kapouer) in #796, Mar 2026.)

Reproduction (CLI 0.82.0, git 2.52)

  1. git init main && (cd main && git commit --allow-empty -m init && git worktree add --relative-paths ../wt)
  2. Add wt/.devcontainer/devcontainer.json with a custom workspaceMount, e.g.:
    { "image": "mcr.microsoft.com/devcontainers/base:debian",
      "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
      "workspaceFolder": "/workspace" }
  3. devcontainer up --workspace-folder wt --mount-git-worktree-common-dir true
  4. devcontainer exec --workspace-folder wt -- git -C /workspace status → fatal: not a git repository: (null)
  5. docker inspect on the container shows only the workspace bind mount; the worktree common dir was not mounted.

Removing workspaceMount makes it work — confirming the guard is the cause.

Expected

The common-dir mount should be computed and added even when a custom workspaceMount is set, by resolving the mount target relative to the configured workspaceMount target / workspaceFolder. This is the common case for monorepos that mount a parent directory and set workspaceFolder to a subpath. Relates to #796.

Workaround

Adding the common dir manually via a mounts entry (binding the main repo's .git to the path the worktree's .git file resolves to inside the container) restores in-container git — matching the maintainer's earlier suggestion in #796.

Activity

  1. AvishayHirsh commented on Jun 8, 2026

    @AvishayHirsh
    Author

    Workaround until this is fixed. The CLI skips the worktree common-dir mount whenever workspaceMount is set — so add it yourself with a mounts entry and --override-config. This script derives the correct mount for your worktree layout (sibling or nested) and brings the container up:

    #!/usr/bin/env bash
    # Worktree + custom workspaceMount: make in-container git work via an extra common-dir mount.
    # Run from the folder with your .devcontainer/ :
    #   bash fix-worktree-dc.sh                  -> just prints the "mounts" line to add
    #   bash fix-worktree-dc.sh --up             -> also brings the container up (devcontainer CLI)
    #   bash fix-worktree-dc.sh /workspaces --up -> non-/workspace workspaceMount target + bring up
    set -euo pipefail
    
    WMT=/workspace; APPLY=0
    for a in "$@"; do case "$a" in --up) APPLY=1;; *) WMT="$a";; esac; done
    
    ROOT="$(git rev-parse --show-toplevel)"
    [ -f "$ROOT/.git" ] || { echo "Not a git worktree — nothing to do."; exit 1; }
    MAIN_GIT="$(cd "$(git rev-parse --git-common-dir)" && pwd)"
    REL="$(sed -n 's/^gitdir: //p' "$ROOT/.git")"
    TARGET="$(python3 -c "import posixpath;print(posixpath.normpath('$WMT/$REL/../..'))")"
    echo "mounts entry:  source=$MAIN_GIT,target=$TARGET,type=bind"
    
    if [ "$APPLY" = 1 ]; then
      python3 - "$MAIN_GIT" "$TARGET" <<'PY'
    import json, re, sys
    s = re.sub(r",(\s*[}\]])", r"\1", re.sub(r"//.*", "", open(".devcontainer/devcontainer.json").read()))
    c = json.loads(s); c.setdefault("mounts", []).append(f"source={sys.argv[1]},target={sys.argv[2]},type=bind")
    json.dump(c, open("/tmp/dc-override.json","w"), indent=2)
    PY
      devcontainer up   --workspace-folder . --override-config /tmp/dc-override.json
      devcontainer exec --workspace-folder . -- bash -lc "git config --global --add safe.directory '*' && git status"
    fi

    CLI steps:

    npm i -g @devcontainers/cli                       # if you don't have it
    cd path/to/your/worktree/<...>/                   # the folder containing .devcontainer/
    bash fix-worktree-dc.sh --up                      # mounts main .git + brings the container up
    # then run anything in the container — git now resolves:
    devcontainer exec --workspace-folder . -- bash -lc "git status && ./gradlew build"

    The override goes to a throwaway file, so your committed devcontainer.json is untouched. (Prefer to make it permanent? run without --up, copy the printed mounts line into devcontainer.json.)

    Layout-agnostic — TARGET = normalize(<workspaceMount target> + <relative gitdir from .git> + /../..): nested worktree → /.git, sibling worktree → /<repo>/.git. Requires a relative-paths worktree (git worktree add --relative-paths, git ≥ 2.48).

    (VS Code / "Reopen in Container" variant: microsoft/vscode-remote-release#11478 (comment))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions