From marcgit
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".
How this skill is triggered — by the user, by Claude, or both
Slash command
/marcgit:marcgitThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
`marcgit` is a git worktree manager. Each project is laid out as a `trunk/`
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/login →
feat-login. No nested subfolders are created.
mgmg 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:
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.🌱/🧹 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 | 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:
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.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.
src="$(git rev-parse --show-toplevel)"
feat/login). Confirm the name if it's ambiguous.dst="$(marcgit work feat/login)"
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.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.
dst="$(marcgit pr 42)", then operate in $dst.
Requires gh authenticated for the repo.marcgit trunk (path on stdout).marcgit list.marcgit remove feat/login (force-removes
worktree + branch; confirm with the user since it deletes the branch).marcgit prune 30 -n
first, show the list, then marcgit prune 30 with user sign-off.marcgit new <name> or
marcgit clone <url> <name>.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./ → -); 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."Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub marc2332/git --plugin marcgit