Problem
When act is run from a git worktree, container-based jobs fail because the .git entry is a file (pointer to the main repo's .git/worktrees/<name>/ directory) rather than a self-contained .git/ directory. Docker containers cannot follow this pointer back to the host filesystem, causing failures in actions/checkout and any step that needs git metadata.
Additionally, when a non-worktree repo contains worktree checkout directories (e.g., .claude/worktrees/ created by Claude Code), docker cp fails because the .git pointer files inside those subdirectories collide during tar extraction with "file exists" errors.
Relates to #657 (closed without resolution).
Proposed Fix
Two changes:
1. Worktree reconstitution (pkg/common/git/worktree.go)
When act detects that .git is a file (worktree indicator), it:
- Parses the
.git file to find the worktree's gitdir
- Reads
commondir to locate the main repo's .git/ directory
- Creates a temp directory with a copy of the working tree (excluding
.git)
- Builds a self-contained
.git/ directory by copying commondir contents and overlaying worktree-specific files (HEAD, index, etc.)
- Uses this temp directory as the bind mount source for the container
The temp directory is cleaned up when the job container closes.
2. Skip .git entries in subdirectories (pkg/filecollector/file_collector.go)
The FileCollector used by CopyDir (which creates the tar archive for docker cp) now skips .git entries (files or directories) at all directory levels, not just the root. These are git-internal metadata and should never be copied into the container. This fixes the case where a parent repo contains worktree checkout directories — their .git pointer files no longer cause docker cp to fail with "file exists" errors.
Testing
- Unit tests for worktree detection,
.git file parsing, commondir resolution, and the copy logic
- Manual testing with Docker/Podman against repos using
git worktree
Environment
- Tested on Windows (Git Bash + Podman) and designed to work cross-platform
- Affects both
--bind and volume-based (default) workspace modes
This issue was created with assistance from Claude Code (Claude Opus 4.6).
Problem
When
actis run from a git worktree, container-based jobs fail because the.gitentry is a file (pointer to the main repo's.git/worktrees/<name>/directory) rather than a self-contained.git/directory. Docker containers cannot follow this pointer back to the host filesystem, causing failures inactions/checkoutand any step that needs git metadata.Additionally, when a non-worktree repo contains worktree checkout directories (e.g.,
.claude/worktrees/created by Claude Code),docker cpfails because the.gitpointer files inside those subdirectories collide during tar extraction with "file exists" errors.Relates to #657 (closed without resolution).
Proposed Fix
Two changes:
1. Worktree reconstitution (
pkg/common/git/worktree.go)When
actdetects that.gitis a file (worktree indicator), it:.gitfile to find the worktree's gitdircommondirto locate the main repo's.git/directory.git).git/directory by copyingcommondircontents and overlaying worktree-specific files (HEAD,index, etc.)The temp directory is cleaned up when the job container closes.
2. Skip
.gitentries in subdirectories (pkg/filecollector/file_collector.go)The
FileCollectorused byCopyDir(which creates the tar archive fordocker cp) now skips.gitentries (files or directories) at all directory levels, not just the root. These are git-internal metadata and should never be copied into the container. This fixes the case where a parent repo contains worktree checkout directories — their.gitpointer files no longer causedocker cpto fail with "file exists" errors.Testing
.gitfile parsing,commondirresolution, and the copy logicgit worktreeEnvironment
--bindand volume-based (default) workspace modesThis issue was created with assistance from Claude Code (Claude Opus 4.6).