marcgit

star 4

Use when the user wants to manage git worktrees with marcgit (a.k.a. `mg`) — creating a worktree for a feature/branch/PR, switching to trunk, listing or pruning worktrees, or moving in-progress edits into a fresh worktree. Triggers on phrases like "marcgit", "mg work", "create a worktree", "make a worktree for this feature", "spin up a branch worktree", "checkout PR N as a worktree", "prune old worktrees".

marc2332 By marc2332 schedule Updated 5/30/2026

name: marcgit description: Use when the user wants to manage git worktrees with marcgit (a.k.a. mg) — creating a worktree for a feature/branch/PR, switching to trunk, listing or pruning worktrees, or moving in-progress edits into a fresh worktree. Triggers on phrases like "marcgit", "mg work", "create a worktree", "make a worktree for this feature", "spin up a branch worktree", "checkout PR N as a worktree", "prune old worktrees".

marcgit (mg)

marcgit is a git worktree manager. Each project is laid out as a trunk/ directory (the main worktree) plus sibling folders next to it, one per branch / PR:

myproject/
├── trunk/        # main worktree — the anchor, never rename it
├── feat-login/   # mg work feat/login
└── fix-typo/     # mg pr 42  (PR head branch fix/typo)

A branch name's slashes become dashes in the folder name: feat/loginfeat-login. No nested subfolders are created.

CRITICAL: call the binary directly, not mg

mg is a shell function users install into their interactive shell (eval "$(marcgit init bash)"). It will not exist in the non-interactive shell you run Bash commands in. Always invoke the real binary marcgit, and handle the printed path yourself.

How output works:

  • Navigating commands (work, pr, new, clone, trunk) print the target directory to stdout (the mg wrapper would cd there). Capture stdout to learn where the worktree is.
  • Everything else (status/info, 🌱/🧹 messages) goes to stderr.

So instead of relying on cd, capture the path and act on it explicitly:

dir="$(marcgit work feat/login)"   # stdout = new/existing worktree path
git -C "$dir" status               # operate without changing your own cwd

If marcgit is not on PATH, tell the user to install it (cargo install --git https://github.com/marc2332/git); do not silently fall back to raw git worktree unless they ask.

Command reference

Command Alias Effect stdout
marcgit new <project> n Create <project>/trunk and git init -b main it. trunk path
marcgit clone <url> <project> c Clone <url> into <project>/trunk. trunk path
marcgit work <branch> w Create (or jump to) a sibling worktree for <branch>; creates the branch off trunk's HEAD if it doesn't exist. Idempotent. worktree path
marcgit pr <number> p Use gh to resolve PR #N's head branch, fetch it (pull/N/head), add a worktree named after that branch. Idempotent. Needs gh. worktree path
marcgit trunk t Resolve the project's trunk path. trunk path
marcgit list l git worktree list for the current project. listing
marcgit remove <branch> r Force-remove the worktree and delete its branch, then point back at trunk. trunk path
marcgit prune <days> [-n|--dry-run] Remove sibling worktrees whose last commit is older than <days> days. Prompts [y/N] on stdin and skips dirty/stashed worktrees. -n previews only.
marcgit init <bash|zsh|fish|nushell> Print the shell wrapper code. wrapper
marcgit config init Write a default marcgit.toml at the project root. config path
marcgit config path Print the marcgit.toml reachable from cwd. config path

Notes:

  • Every command except new, clone, and init must run inside a project (any worktree of it). marcgit finds the project by locating the worktree literally named trunk. If it errors with "no trunk worktree found", you're not in a marcgit project — use marcgit new/clone first, or cd into one.
  • work and pr are idempotent: if the folder already exists they just return its path.
  • prune blocks on a y/N confirmation prompt. When running it non-interactively, always do a --dry-run first, show the user what would be pruned, and only then run the real prune (piping yes only with explicit user approval). Never auto-confirm destructive prunes.
  • config init: init-submodules = true (default) makes work/pr run git submodule update --init --recursive when a .gitmodules exists.

Workflow: "create a worktree for this feature and copy my changes into it"

This is the headline use case. The user is working in one worktree (often trunk), has in-progress edits, and wants a clean feature worktree that contains those same edits. Literally copy the file edits across.

  1. Identify the source worktree — your current location, or the path the user names. Capture its absolute path:
    src="$(git rev-parse --show-toplevel)"
    
  2. Pick the branch name from what the user said (e.g. "login feature" → feat/login). Confirm the name if it's ambiguous.
  3. Create the worktree and capture its path:
    dst="$(marcgit work feat/login)"
    
  4. Copy the edits from src into dst. Cover both tracked and untracked:
    # tracked, staged + unstaged modifications → as a patch
    git -C "$src" diff HEAD > /tmp/mg-feature.patch
    if [ -s /tmp/mg-feature.patch ]; then
        git -C "$dst" apply /tmp/mg-feature.patch
    fi
    # untracked files → copy verbatim, preserving relative paths
    git -C "$src" ls-files --others --exclude-standard -z |
        while IFS= read -r -d '' f; do
            mkdir -p "$dst/$(dirname "$f")"
            cp -p "$src/$f" "$dst/$f"
        done
    
    If git apply fails (e.g. the worktree branched from a different base), fall back to a 3-way apply: git -C "$dst" apply --3way /tmp/mg-feature.patch, and if that still conflicts, tell the user which files conflicted instead of guessing.
  5. Verify the copy landed and report the destination:
    git -C "$dst" status --short
    
    Tell the user the new worktree path ($dst) and what was copied.

Decide tracked-vs-everything by intent: git diff HEAD carries every change relative to the last commit (staged + unstaged). If the user only wants specific files, scope the patch with pathspecs: git -C "$src" diff HEAD -- path/a path/b.

Do NOT remove the edits from the source unless the user asks to move (not copy) them. If they want a move, after verifying the copy you can git -C "$src" checkout -- . / clean untracked — but confirm first, it's destructive.

When the user instead describes a feature in prose (no existing edits), just create the worktree (step 3), cd/operate inside $dst, and implement the work there fresh.

Other common requests

  • "work on PR 42"dst="$(marcgit pr 42)", then operate in $dst. Requires gh authenticated for the repo.
  • "go back to trunk"marcgit trunk (path on stdout).
  • "what worktrees exist"marcgit list.
  • "delete the login worktree"marcgit remove feat/login (force-removes worktree + branch; confirm with the user since it deletes the branch).
  • "clean up stale worktrees older than 30 days"marcgit prune 30 -n first, show the list, then marcgit prune 30 with user sign-off.
  • "start a new project"marcgit new <name> or marcgit clone <url> <name>.

Gotchas

  • The shell wrapper only cds when stdout is a single existing directory; multi-line output (like list) is printed, not cd'd. You read stdout directly anyway, so this only matters when you advise the user.
  • Folder names are sanitized (/-); when you need the folder for a branch, derive it the same way, or just trust the path marcgit prints.
  • prune measures age by each worktree's last commit (git log -1) and refuses worktrees with uncommitted changes, untracked files, or stashes on their branch — so "nothing to prune" can mean "all candidates were dirty."
Install via CLI
npx skills add https://github.com/marc2332/git --skill marcgit
Repository Details
star Stars 4
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator