Skip to content

Commit 5d528cd

Browse files
andrewleechclaude
andcommitted
Fix Docker builds for git worktrees by mounting main .git directory
When building from a git worktree, the .git file contains a path to the actual .git directory. The Docker container needs access to the main .git directory to properly resolve git information and update submodules. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 3a4cc19 commit 5d528cd

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

src/mpbuild/build.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,81 @@
1414
from . import board_database, find_mpy_root
1515
from .board_database import Board
1616

17+
18+
def get_git_directory(mpy_dir: Path) -> Path | None:
19+
"""
20+
Get the actual .git directory path, handling both regular repos and worktrees.
21+
22+
Args:
23+
mpy_dir: Path to the MicroPython repository root
24+
25+
Returns:
26+
Path to the actual .git directory, or None if not found
27+
"""
28+
git_path = mpy_dir / ".git"
29+
30+
if not git_path.exists():
31+
return None
32+
33+
if git_path.is_dir():
34+
# Regular git repository
35+
return git_path
36+
elif git_path.is_file():
37+
# Git worktree - .git file contains path to actual .git directory
38+
try:
39+
git_file_content = git_path.read_text().strip()
40+
if git_file_content.startswith("gitdir: "):
41+
gitdir_path = git_file_content[8:] # Remove "gitdir: " prefix
42+
return Path(gitdir_path).resolve()
43+
except (OSError, ValueError):
44+
pass
45+
46+
return None
47+
48+
49+
def get_main_git_directory(mpy_dir: Path) -> Path | None:
50+
"""
51+
Get the main .git directory for repos and worktrees.
52+
53+
For regular repos, returns None (no additional mount needed).
54+
For worktrees, returns the common git directory that needs to be mounted.
55+
56+
Args:
57+
mpy_dir: Path to the MicroPython repository root
58+
59+
Returns:
60+
Path to the main .git directory, or None if not needed
61+
62+
Raises:
63+
RuntimeError: If git command is not available
64+
"""
65+
try:
66+
result = subprocess.run(
67+
["git", "rev-parse", "--git-common-dir"],
68+
cwd=mpy_dir,
69+
capture_output=True,
70+
text=True,
71+
timeout=5,
72+
)
73+
if result.returncode == 0:
74+
git_common_dir = Path(result.stdout.strip()).resolve()
75+
if git_common_dir.exists() and git_common_dir.is_dir():
76+
# If the git directory is already within mpy_dir, no mount needed
77+
if git_common_dir.is_relative_to(mpy_dir):
78+
return None
79+
return git_common_dir
80+
except FileNotFoundError:
81+
raise RuntimeError(
82+
"Git command not found. Please install git to build with mpbuild."
83+
)
84+
except subprocess.TimeoutExpired:
85+
raise RuntimeError(
86+
"Git command timed out. Check git installation and repository state."
87+
)
88+
89+
return None
90+
91+
1792
ARM_BUILD_CONTAINER = "micropython/build-micropython-arm"
1893
BUILD_CONTAINERS = {
1994
"stm32": ARM_BUILD_CONTAINER,
@@ -107,6 +182,12 @@ def docker_build_cmd(
107182

108183
mpy_dir = str(port.directory_repo)
109184

185+
# Handle git worktrees by mounting the main .git directory
186+
git_volume_mount = ""
187+
main_git_dir = get_main_git_directory(Path(mpy_dir))
188+
if main_git_dir:
189+
git_volume_mount = f"-v {main_git_dir}:{main_git_dir} "
190+
110191
# Dynamically find all ttyACM and ttyUSB devices
111192
tty_devices = []
112193
for pattern in ["/dev/ttyACM*", "/dev/ttyUSB*"]:
@@ -125,6 +206,7 @@ def docker_build_cmd(
125206
f"{'-it ' if docker_interactive else ''}"
126207
f"{device_flags}" # provides access to USB and serial devices for deploy
127208
f"-v {mpy_dir}:{mpy_dir} -w {mpy_dir} " # mount micropython dir with same path so elf/map paths match host
209+
f"{git_volume_mount}" # mount actual .git directory for worktrees
128210
f"--user {uid}:{gid} " # match running user id so generated files aren't owned by root
129211
f"-e HOME=/tmp " # set HOME to /tmp for container
130212
f"{build_container} "

0 commit comments

Comments
 (0)