Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

16 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

License: MIT

🚧 marcgit

A fancy git worktree manager. You call it as mg through a shell wrapper.

Projects live at <project>/trunk, and every other worktree (PRs, feature branches) lives as a sibling folder next to trunk:

myproject/
β”œβ”€β”€ trunk/             # main worktree
β”œβ”€β”€ feat-login/        # mg work feat/login
└── fix-typo/          # mg pr 42 (branch: fix/typo)

Features

  • Submodules cache
  • Automatic submodules pulling on worktree creation
  • Seamless integration with GitHub PRs
  • Easy worktree pruning
  • Custom hook on worktree creation

Install

cargo install --git https://github.com/marc2332/git

Then wire the mg shell function into your rc:

# bash
eval "$(marcgit init bash)"

# zsh
eval "$(marcgit init zsh)"

# fish
marcgit init fish | source

# nushell β€” add to config.nu
marcgit init nushell | save -f ~/.config/nushell/marcgit.nu
# then: source ~/.config/nushell/marcgit.nu

The binary prints paths; the wrapper cds to them. Same trick zoxide and direnv use.

mg pr requires gh (GitHub CLI) to look up the PR's branch name.

Commands

Command What it does
mg new <name> / mg n Create ./<name>/trunk and git init it. Jump in.
mg clone <url> <name> / mg c Clone a repo into ./<name>/trunk. Jump in.
mg work <branch> / mg w Create (or jump to) a sibling worktree for <branch>. Creates branch if new. --still to set it up without jumping in.
mg pr <number> / mg p Fetch the PR via gh, create a worktree named after its head branch, jump in. --still to set it up without jumping in.
mg trunk / mg t Jump to the project's trunk from any sibling worktree.
mg list / mg l Print git worktree list for the current project.
mg remove <branch> / mg r Remove the worktree and delete its branch. Jump back to trunk.
mg prune <days> Remove sibling worktrees whose last commit is older than <days> days. Asks for confirmation; skips worktrees with modified or stashed files. -n / --dry-run to preview.
mg init <shell> Print the shell wrapper for bash / zsh / fish / nushell.
mg config init Write a default marcgit.toml at the project root. Print its path.
mg config path Print the path of the marcgit.toml reachable from the current directory.

Examples

mg new myproject                              # β†’ ./myproject/trunk
mg clone https://github.com/user/repo.git foo # β†’ ./foo/trunk
mg work feat/login                            # β†’ ./myproject/feat-login (branch feat/login)
mg pr 42                                      # β†’ ./myproject/fix-typo (PR #42's head branch)
mg pr 42 --still                              # same, but stay in the current directory
mg trunk                                      # β†’ ./myproject/trunk
mg remove feat/login                          # removes worktree + branch
mg prune 30                                   # prune worktrees idle β‰₯ 30 days (asks first)
mg prune 30 -n                                # dry-run: just list what would be pruned

Notes

  • Slashes in a branch name become dashes in the folder β€” feat/login β†’ feat-login. No nested subfolders.
  • mg work and mg pr are idempotent: if the worktree already exists, they just jump.
  • --still on mg work / mg pr prints the worktree path to stderr instead of stdout, so the shell wrapper has nothing to cd into and you stay put.
  • mg pr requires gh (GitHub CLI) to look up the PR's head branch name.
  • mg prune measures age by each worktree's last commit date (git log -1). It refuses to remove worktrees with uncommitted changes, untracked files, or stashes recorded against their branch.

Config

Optional marcgit.toml at the project root (next to trunk/). mg config init writes the default:

init-submodules = true         # pull submodules on `mg work` (default: true)
cache-submodules = true        # reuse submodule clones from ~/.mg/cache/submodules (default: true)
# create-hook = "npm install"  # shell command run inside a newly created worktree

create-hook runs after the worktree (and its submodules) are set up, with the new worktree as working directory. Its output goes to stderr so it doesn't interfere with the cd wiring. A failing hook prints a warning but doesn't abort β€” you still land in the new worktree.

With cache-submodules on, each submodule's git directory is cached globally in ~/.mg/cache/submodules/<repo>/<commit-sha>/ (up to 5 versions per repo, LRU). When a new worktree initializes submodules, a cached copy is seeded into place first so git submodule update checks out from local objects instead of cloning over the network. The result is still a completely normal submodule.

How it finds the project

Every command other than new, clone, and init needs to know which project you're in. It runs git worktree list --porcelain and picks the worktree whose folder is literally named trunk. That's the anchor β€” so don't rename it.

License

MIT Β© Marc EspΓ­n Sanz

About

marcgit 🚧, a git worktree manager that I like

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages