From fed144d27af62fe5f596023e5725f1b926a5ae08 Mon Sep 17 00:00:00 2001 From: Yaroslav Halchenko Date: Fri, 5 Dec 2025 13:44:31 -0500 Subject: [PATCH 1/4] enh: bind mount original repo when running in a git worktree MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the workspace is a git worktree (detected via .git being a symlink or a file with gitdir: reference), add a bind mount for the original repository. This allows Claude to access the original repo's git objects and references, and perform git operations (commit, fetch, etc.). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- bin/yolo | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/bin/yolo b/bin/yolo index 8e1f9f9..8bbaad4 100755 --- a/bin/yolo +++ b/bin/yolo @@ -56,6 +56,40 @@ CLAUDE_HOME_DIR="$HOME/.claude" # must exist but might not if first start on that box mkdir -p "$CLAUDE_HOME_DIR" +# Detect if we're in a git worktree and find the original repo +WORKTREE_MOUNTS=() +gitdir_path="" +dot_git="$(pwd)/.git" + +if [ -L "$dot_git" ]; then + # .git is a symlink - resolve it to get the gitdir path + gitdir_path=$(realpath "$dot_git" 2>/dev/null) +elif [ -f "$dot_git" ]; then + # .git is a file, likely a worktree - read the gitdir path + gitdir_line=$(cat "$dot_git") + if [[ "$gitdir_line" =~ ^gitdir:\ (.+)$ ]]; then + gitdir_path="${BASH_REMATCH[1]}" + # Resolve to absolute path if relative + if [[ "$gitdir_path" != /* ]]; then + gitdir_path="$(pwd)/$gitdir_path" + fi + gitdir_path=$(realpath "$gitdir_path" 2>/dev/null || echo "$gitdir_path") + fi +fi + +if [ -n "$gitdir_path" ]; then + # gitdir_path is typically /path/to/original/repo/.git/worktrees/ + # We need to find the original repo's .git directory + if [[ "$gitdir_path" =~ ^(.+/\.git)/worktrees/ ]]; then + original_git_dir="${BASH_REMATCH[1]}" + original_repo_dir=$(dirname "$original_git_dir") + # Only add if it's different from our current workspace + if [ "$original_repo_dir" != "$(pwd)" ]; then + WORKTREE_MOUNTS+=("-v" "$original_repo_dir:$original_repo_dir:Z") + fi + fi +fi + # Determine paths based on --anonymized-paths flag if [ "$USE_ANONYMIZED_PATHS" -eq 1 ]; then # Old behavior: use anonymized paths @@ -87,6 +121,7 @@ podman run -it --rm \ -v "$CLAUDE_MOUNT" \ -v "$HOME/.gitconfig:/tmp/.gitconfig:ro,Z" \ -v "$WORKSPACE_MOUNT" \ + "${WORKTREE_MOUNTS[@]}" \ -w "$WORKSPACE_DIR" \ -e CLAUDE_CONFIG_DIR="$CLAUDE_DIR" \ -e GIT_CONFIG_GLOBAL=/tmp/.gitconfig \ From d510a8f01ba5f39770ae10cce7bf7da688ccd3a8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 6 Dec 2025 16:21:36 +0000 Subject: [PATCH 2/4] Add --worktree option with ask/bind/ok/error modes Co-Authored-By: Austin Macdonald Co-Authored-By: Claude Opus 4.5 --- README.md | 25 +++++++++++++++++++++++++ bin/yolo | 45 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cee94ad..005336c 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,31 @@ If you prefer the old behavior with anonymized paths (`/claude` and `/workspace` yolo --anonymized-paths ``` +### Git Worktree Support + +When running in a git worktree, `yolo` can detect and optionally bind mount the original repository. This allows Claude to access git objects and perform operations like commit and fetch. Control this behavior with the `--worktree` option: + +- `--worktree=ask` (default): Prompts whether to bind mount the original repo +- `--worktree=bind`: Automatically bind mounts the original repo +- `--worktree=ok`: Skip bind mounting without error +- `--worktree=error`: Exit with error if running in a worktree + +```bash +# Prompt for bind mount decision (default) +yolo + +# Always bind mount in worktrees +yolo --worktree=bind + +# Never bind mount, run without error +yolo --worktree=ok + +# Disallow running in worktrees +yolo --worktree=error +``` + +**Security note**: Bind mounting the original repo exposes more files and allows modifications. The prompt helps prevent unintended access. + > **TODO**: Add curl-based one-liner setup once this PR is merged ## First-Time Login diff --git a/bin/yolo b/bin/yolo index 8bbaad4..e3042e3 100755 --- a/bin/yolo +++ b/bin/yolo @@ -4,12 +4,13 @@ set -e # Parse arguments: everything before -- goes to podman, everything after goes to claude -# Also check for --anonymized-paths and --entrypoint flags +# Also check for --anonymized-paths, --entrypoint, and --worktree flags PODMAN_ARGS=() CLAUDE_ARGS=() found_separator=0 USE_ANONYMIZED_PATHS=0 ENTRYPOINT="claude" +WORKTREE_MODE="ask" while [ $# -gt 0 ]; do case "$1" in @@ -21,6 +22,16 @@ while [ $# -gt 0 ]; do ENTRYPOINT="${1#--entrypoint=}" shift ;; + --worktree=*) + WORKTREE_MODE="${1#--worktree=}" + # Validate worktree mode + if [[ ! "$WORKTREE_MODE" =~ ^(ask|bind|ok|error)$ ]]; then + echo "Error: Invalid --worktree value: $WORKTREE_MODE" >&2 + echo "Valid values are: ask, bind, ok, error" >&2 + exit 1 + fi + shift + ;; --anonymized-paths) USE_ANONYMIZED_PATHS=1 shift @@ -60,6 +71,8 @@ mkdir -p "$CLAUDE_HOME_DIR" WORKTREE_MOUNTS=() gitdir_path="" dot_git="$(pwd)/.git" +is_worktree=0 +original_repo_dir="" if [ -L "$dot_git" ]; then # .git is a symlink - resolve it to get the gitdir path @@ -83,13 +96,39 @@ if [ -n "$gitdir_path" ]; then if [[ "$gitdir_path" =~ ^(.+/\.git)/worktrees/ ]]; then original_git_dir="${BASH_REMATCH[1]}" original_repo_dir=$(dirname "$original_git_dir") - # Only add if it's different from our current workspace + # Only consider it a worktree if it's different from our current workspace if [ "$original_repo_dir" != "$(pwd)" ]; then - WORKTREE_MOUNTS+=("-v" "$original_repo_dir:$original_repo_dir:Z") + is_worktree=1 fi fi fi +# Handle worktree based on the mode +if [ "$is_worktree" -eq 1 ]; then + case "$WORKTREE_MODE" in + error) + echo "Error: Running in a git worktree is not allowed with --worktree=error" >&2 + echo "Original repo: $original_repo_dir" >&2 + exit 1 + ;; + bind) + WORKTREE_MOUNTS+=("-v" "$original_repo_dir:$original_repo_dir:Z") + ;; + ok) + # Do nothing - skip bind mount + ;; + ask) + echo "Detected git worktree. Original repository: $original_repo_dir" >&2 + echo "Bind mounting the original repo allows git operations but may expose unintended files." >&2 + read -p "Bind mount original repository? [y/N] " -n 1 -r >&2 + echo >&2 + if [[ $REPLY =~ ^[Yy]$ ]]; then + WORKTREE_MOUNTS+=("-v" "$original_repo_dir:$original_repo_dir:Z") + fi + ;; + esac +fi + # Determine paths based on --anonymized-paths flag if [ "$USE_ANONYMIZED_PATHS" -eq 1 ]; then # Old behavior: use anonymized paths From 7e778a74294851fbda01131d84339d9b4195a89b Mon Sep 17 00:00:00 2001 From: Austin Macdonald Date: Tue, 9 Dec 2025 12:39:21 -0600 Subject: [PATCH 3/4] docs: clarify --worktree=ok description Co-Authored-By: Austin Macdonald Co-Authored-By: Claude Opus 4.5 Co-Authored-By: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 005336c..51b6db5 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ When running in a git worktree, `yolo` can detect and optionally bind mount the - `--worktree=ask` (default): Prompts whether to bind mount the original repo - `--worktree=bind`: Automatically bind mounts the original repo -- `--worktree=ok`: Skip bind mounting without error +- `--worktree=ok`: Skip bind mounting and continue normally - `--worktree=error`: Exit with error if running in a worktree ```bash From 48eec7361e1f967141d3a60f4032af4e494ae36a Mon Sep 17 00:00:00 2001 From: Austin Macdonald Date: Thu, 11 Dec 2025 13:11:52 -0600 Subject: [PATCH 4/4] rename --worktree=ok to --worktree=skip More intuitive name for the option that skips bind mounting. Co-Authored-By: Austin Macdonald Co-Authored-By: Claude Opus 4.5 --- README.md | 6 +++--- bin/yolo | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 51b6db5..da8ca9a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ When running in a git worktree, `yolo` can detect and optionally bind mount the - `--worktree=ask` (default): Prompts whether to bind mount the original repo - `--worktree=bind`: Automatically bind mounts the original repo -- `--worktree=ok`: Skip bind mounting and continue normally +- `--worktree=skip`: Skip bind mounting and continue normally - `--worktree=error`: Exit with error if running in a worktree ```bash @@ -45,8 +45,8 @@ yolo # Always bind mount in worktrees yolo --worktree=bind -# Never bind mount, run without error -yolo --worktree=ok +# Skip bind mounting, continue normally +yolo --worktree=skip # Disallow running in worktrees yolo --worktree=error diff --git a/bin/yolo b/bin/yolo index e3042e3..c557ff0 100755 --- a/bin/yolo +++ b/bin/yolo @@ -25,9 +25,9 @@ while [ $# -gt 0 ]; do --worktree=*) WORKTREE_MODE="${1#--worktree=}" # Validate worktree mode - if [[ ! "$WORKTREE_MODE" =~ ^(ask|bind|ok|error)$ ]]; then + if [[ ! "$WORKTREE_MODE" =~ ^(ask|bind|skip|error)$ ]]; then echo "Error: Invalid --worktree value: $WORKTREE_MODE" >&2 - echo "Valid values are: ask, bind, ok, error" >&2 + echo "Valid values are: ask, bind, skip, error" >&2 exit 1 fi shift @@ -114,7 +114,7 @@ if [ "$is_worktree" -eq 1 ]; then bind) WORKTREE_MOUNTS+=("-v" "$original_repo_dir:$original_repo_dir:Z") ;; - ok) + skip) # Do nothing - skip bind mount ;; ask)