worktrees
Git worktree commands that refuse to lose work.
gws, gwp, gwnb, gwrot and gwh answer a question and print it. gwa, gwl, gwm and gwr land you somewhere, and each of those needs a shell function, because a binary cannot change its caller's directory.
| | | | --- | --- | | gws | say which worktrees are finished, and why. Removes nothing, and has no flag that could | | gwp | remove the ones gws marks removable, having asked first | | gwa NAME [BASE] | create a worktree for NAME and land you in it | | gwl [QUERY] | pick one of this repository's worktrees and land you in it | | gwm NEW | rename this worktree's branch and move the checkout to match | | gwr [QUERY] | remove a worktree whose branch is finished, and the branch | | gwnb NAME | alpha. Fetch, then branch NAME off the head branch and check it out | | gwrot | alpha. Start the next branch after this one, or catch the head branch up | | gwh | print that table, with every name each command answers to |
gw takes the same commands as subcommands, each with shorthands, so gwl, gw list, gw ls and gw l are one command:
| | | | --- | --- | | gws | gw status, st, s | | gwp | gw prune, p | | gwa | gw add, a | | gwl | gw list, ls, l | | gwm | gw move, mv, m | | gwr | gw remove, rm | | gwnb | gw new-branch, nb, new | | gwrot | gw rotate, rot | | gwh | gw help, h, and gw with no subcommand |
worktrees is the same program under its long name.
Ctrl-C interrupts a running command with exit code 130 and no traceback. At a selection or removal prompt, it cancels without choosing or removing a worktree.
gws and gwp are what this tool is for and their behaviour is settled.
gwnb and gwrot are alpha and may go. They start branches rather than worktrees, which is a different job from the one this repository exists to do, and origin new-branch and origin rotate already do it. Only one of the two sets survives. Until that is decided the names, the flags and the output may change, and nothing should be built on top of them.
Two holes in git
A squash merge inverts git branch -d
A branch whose change is already in main reports error: the branch 'x' is not fully merged and points you at -D, which deletes anything. By hand, squashed and unmerged are indistinguishable: both report NOT merged, both sit one commit ahead. Opposite correct actions, no signal between them.
The probe that separates them replays the branch's tree as one commit on the merge base and asks git cherry whether that patch is already upstream. It compares content rather than history, which is what a squash preserves.
A branch that probe proves is deleted with its checkout. The delete names the sha the ref must still hold, so a commit landing between the verdict and the removal fails it rather than going with it, and the command that puts the branch back is printed before anything runs.
git worktree remove silently deletes ignored files
With .env and nodemodules/ present, git status --porcelain prints nothing, git worktree remove exits 0 with no --force, and both are gone. Nothing in git brings them back: no ref ever pointed at them. gws reads --ignored=traditional, counts what would go, and marks the worktree keep until you pass --delete-ignored.