Open-source project
k1LoW/git-wt avatar
k1LoW/git-wt

git-wt: a Git subcommand that makes worktrees simple

A Git subcommand that makes `git worktree` simple

563 stars25 forksGoMIT

At a glance

What is it?
git-wt wraps git worktree in a single command that resolves its target by branch name, directory name or path, creates the worktree and branch if they do not exist, and refuses to delete anything that would lose work. It is a Go program installed with go install or Homebrew, and it comes with a shell wrapper that will change directory for you.
Who is it for?
git-wt fits a developer who works across several branches at once and wants one command that creates the worktree, the branch and the directory together, with the delete and rename paths refusing to lose work by default.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One command for the worktree dance

The README describes git-wt as a Git subcommand that makes `git worktree` simple, and the whole usage table fits in nine lines:

console
$ git wt                            # List all worktrees
$ git wt --json                     # List all worktrees in JSON format
$ git wt <branch|worktree|path>     # Switch to worktree (create worktree/branch if needed)
$ git wt -b <branch> <worktree>     # Create worktree with a different branch name
$ git wt --orphan <branch|worktree> # Create worktree with a new orphan branch (Git 2.42+)
$ git wt -d <branch|worktree|path>  # Delete worktree and branch (safe)
$ git wt -D <branch|worktree|path>  # Force delete worktree and branch
$ git wt -m [<old>] <new>           # Rename worktree directory and branch (safe)
$ git wt -M [<old>] <new>           # Force rename (overwrite existing branch, allow moving dirty/locked worktrees)

The line that carries the design is the third one. Running git wt with a name switches to that worktree, creating the worktree and the branch if they do not exist. That single behaviour is what the rest of the tool exists to make safe, because creating a worktree and a branch and then finding yourself in the right directory is three commands in raw git and one in this one.

The primary language is Go, the licence is MIT, and the topics are git and git-worktree. The recent releases are v0.30.0 from 2026-10-08, v0.29.3 from 2026-09-11 and v0.29.2 from 2026-09-09, and the last push to the repository was on 2026-10-15.

The target can be a branch, a directory or a path

The target resolution is the part of the interface that removes ambiguity from git's own, where a worktree is addressed by path and a branch is a separate concept.

The target can be specified as a branch, which is a git branch name, as in git wt feature-branch. It can be a worktree, which is a directory name relative to the configured base directory, by default .wt, as in git wt some-worktree-folder-name. Or it can be a path, a filesystem path that is absolute or relative to the current working directory, pointing at an existing worktree, as in git wt ../sibling or git wt /absolute/path.

So the same name usually resolves without you having to care whether Git currently has that as a branch, as a directory, or as both. If you ask for feature-branch and there is a branch with that name, you get its worktree. If there is a directory with that name under the base directory, you get that directory. If neither exists, you get a new worktree with a branch of that name.

The same target types apply when deleting, so git wt -d feature-branch, git wt -d . and git wt -d ../sibling are all valid, which is what makes the safe delete usable from inside a worktree you are about to remove.

No subcommands, and that is on purpose

There is a note in the README that is worth reading before you type anything, because it is the kind of decision that surprises people:

git-wt has no subcommands. The first non-flag argument is always a target name, never a command, so `git wt list` creates a worktree named `list` instead of listing anything. Run `git wt` with no arguments to list worktrees.

That is a deliberate narrowing of the interface, and it has a real cost. If you have used a tool where git wt list would list things, or where git wt add would add one, the muscle memory will produce a worktree called list or add, and you will find out after the fact.

The reason to accept it is that the alternative is worse. A tool with subcommands needs to distinguish a command from a target, which means reserving words, which means the branch names you can use are constrained, and branch names are exactly the thing you want to type freely. With no subcommands, any name you can think of is a valid branch name, which is why the tool can offer branch, directory and path as interchangeable ways of naming the same thing.

The listing lives at the JSON flag and at the empty invocation. Running git wt with no arguments lists the worktrees, and git wt --json lists them in JSON format for a script to consume.

Deletion and rename refuse to lose work

The delete flags come in a safe and a force form, and the README is precise about what the safe one checks.

The -d flag is the safe form and stops short when something would be lost. If the worktree has modified or untracked files, nothing is deleted. If the branch is not fully merged, the worktree is removed but the branch is kept, and git-wt reports this and still exits 0, so read the message rather than only the exit code.

That exit code detail matters in a script. A deletion that was only partly performed reports success, which means a pipeline that checks the exit status will believe the cleanup finished. The unmerged-branch case is exactly the one where you want to be told.

The -D flag skips both checks and removes the worktree together with its branch.

Rename works the same way. The -m flag renames a worktree's directory and branch in a single operation, with one argument renaming the current worktree and two renaming an explicit one, while -M forces it, overwriting an existing branch and allowing a dirty or locked worktree to be moved. When the rename is invoked through the shell integration on the current worktree, the wrapper changes directory to the new path, in the same way that -d returns to the main repository root after deleting the current worktree.

There is a third protection on top. The default branch, main or master, is protected from accidental deletion or rename. Pass --allow-delete-default to override it. The README spells out the cases: if the default branch has a worktree, -d removes the worktree but keeps the branch by default, and -m or -M refuses to rename it; if the default branch has no worktree, deletion is refused by default.

Orphan worktrees, and the copy settings that do not apply to them

The --orphan flag creates a worktree with a new orphan branch, which has no history and starts from an empty working tree. The typical use is a static site or documentation branch that has nothing to do with the main history:

console
$ git wt --orphan gh-pages

Three constraints come with it. It requires Git 2.42 or later, which added `git worktree add --orphan`. It can be combined with -b, but not with a start-point, and it fails when the branch or the worktree already exists. And no files are copied into the new worktree, whatever `wt.copyignored`, `wt.copyuntracked`, `wt.copymodified`, `wt.copy` and `wt.symlink` (or their flags) say, so that it starts clean. Hooks still run.

That third point is a design decision worth pausing on. The copy settings exist so that a new worktree picks up your local configuration, ignored files and untracked assets, which is what you usually want when you branch off to work on a feature. For an orphan branch you usually want the opposite, and a tool that quietly copied your local .env into a fresh history would be doing you a disservice. The price is that the flags have no effect in that mode, which the README states rather than leaving you to discover it.

The shell wrapper, and the last-line-of-stdout contract

The shell integration is what turns git-wt into a directory-changing command, and it is installed by evaluating an init script for your shell.

For zsh:

zsh
eval "$(git wt --init zsh)"

For bash, which the README marks as experimental:

bash
eval "$(git wt --init bash)"

For fish and PowerShell, both also marked experimental, the forms are different:

fish
git wt --init fish | source
powershell
Invoke-Expression (git wt --init powershell | Out-String)

The integration creates a `git()` wrapper function to enable automatic directory switching with `git wt <branch>`, and the README is candid that this wrapper intercepts only `git wt <branch>` commands and passes all other git commands through unchanged. It also warns that if you have other tools or customizations that also wrap the `git` command, there may be conflicts, which is the real cost of this approach.

Underneath, the contract is precise and it is the part scripts depend on. The cd is performed by that wrapper function, so it only exists in a shell that sourced the script above. The binary itself always prints the resulting worktree path as the last line of stdout, which is what the wrapper reads. Git's own progress output and hook output both go to stderr, so scripts, editors and other tools can rely on the last line:

console
$ WT=$(git wt --nocd feature-branch | tail -1)
$ git -C "$WT" status

If you want completion without the git() wrapper, you use --nocd at init time, and the same flag on a normal invocation creates or switches to a worktree without changing the current directory, printing the path instead.

Installing it, and configuring the base directory

There are three installation routes, and they are one command each.

With go install:

console
$ go install github.com/k1LoW/git-wt@latest

With a Homebrew tap:

console
$ brew install k1LoW/tap/git-wt

Or manually, by downloading the binary from the releases page.

Configuration is done via `git config`, and every option can be overridden with a flag for a single invocation. The main one is wt.basedir, the worktree base directory:

console
$ git config wt.basedir "../{gitroot}-worktrees"
# or override for a single invocation
$ git wt --basedir="/tmp/worktrees" feature-branch

The only supported template variable is {gitroot}, the repository root directory name, so a project called payments would get worktrees in ../payments-worktrees by default rather than a shared .wt directory. The default base directory is .wt.

The README attaches a caution to the default. When placing worktrees inside the repository, for example .wt, be aware of these limitations, and the first of them is that configuration files are loaded multiple times by tools that traverse parent directories, with the example given being Claude. That is a real and specific problem: a tool that walks up the directory tree will find the same .editorconfig, .eslintrc or similar twice and apply it twice.

The Go side of the repository is a conventional one. The module is github.com/k1LoW/git-wt and it targets go 1.26.8, with go-git for the Git plumbing, cobra for the command line, tablewriter for the listing output and the author's own exec helper for shelling out. The Makefile covers the usual ground, with test running the suite under a coverage profile, build and install stamping the revision into the binary, lint combining golangci-lint with gostyle, and a credits target that regenerates the CREDITS file with gocredits.

Editorial conclusion

git-wt fits a developer who works across several branches at once and wants one command that creates the worktree, the branch and the directory together, with the delete and rename paths refusing to lose work by default. It is the wrong choice if you want to keep your own muscle memory for raw git worktree commands, since it deliberately has no subcommands and any word you type is treated as a target, and the wrong choice on a machine whose Git is older than 2.42 if you need orphan worktrees. Verify first that your Git version supports the orphan mode if you need it, that your shell integration does not conflict with another git wrapper, and whether you want worktrees inside the repository, since the README flags configuration files being loaded more than once in that case.

Frequently asked questions

What does git-wt do?

It is a Git subcommand that makes git worktree simple. Running git wt with a branch name, worktree directory name or filesystem path switches to that worktree and creates the worktree and branch if they do not already exist, and it also supports listing, safe and forced deletion, renaming and orphan branches.

How do I install git-wt?

With go install github.com/k1LoW/git-wt@latest, with brew install k1LoW/tap/git-wt from the author's tap, or by downloading the binary from the releases page. The shell integration for zsh, bash, fish and PowerShell is installed separately with git wt --init followed by the shell name.

Does git-wt have subcommands?

No. The README is explicit that git-wt has no subcommands, so the first non-flag argument is always a target name, never a command. Running git wt list creates a worktree named list, and running git wt with no arguments lists the worktrees.

What is the difference between git wt -d and git wt -D?

The -d form is safe: if the worktree has modified or untracked files nothing is deleted, and if the branch is not fully merged the worktree is removed but the branch is kept, with git-wt reporting that and still exiting 0. The -D form skips both checks and removes the worktree together with its branch.

How do I make git-wt change directory for me?

Add the init script for your shell to your shell config, for example eval "$(git wt --init zsh)" in zsh. That creates a git() wrapper which intercepts only git wt <branch> commands and passes everything else through. If you only want completion, use the --nocd option instead.

Official sources

  1. Issues
  2. k1LoW/git-wt on GitHub
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/k1low-git-wt.svg)](https://hysenlabs.com/projects/k1low-git-wt)