Skip to content

Instantly share code, notes, and snippets.

@lukaszraczylo
Created January 4, 2026 02:49
Show Gist options
  • Select an option

  • Save lukaszraczylo/58c579ec18fb5113d5f3d05a789643ec to your computer and use it in GitHub Desktop.

Select an option

Save lukaszraczylo/58c579ec18fb5113d5f3d05a789643ec to your computer and use it in GitHub Desktop.
git worktree helper / manager
# Git Worktree Manager (bare repo workflow)
# Works in bash and zsh
gwt() {
case "$1" in
init)
shift
_gwt_init "$@"
;;
add | a)
shift
_gwt_add "$@"
;;
fork | f)
shift
_gwt_fork "$@"
;;
jump | j) _gwt_jump ;;
rm)
shift
_gwt_rm "$@"
;;
ls) _gwt_ls ;;
st) _gwt_st ;;
*) _gwt_help ;;
esac
}
_gwt_root() {
local root
root=$(git rev-parse --git-common-dir 2>/dev/null)
if [[ -z "$root" ]] || [[ "$root" == "." ]]; then
if [[ -f "HEAD" ]] && [[ -d "objects" ]] && [[ -d "refs" ]]; then
root=$PWD
else
echo "Not a git repo" >&2
return 1
fi
fi
echo "$root"
}
_gwt_init() {
[[ -z "$1" ]] && {
echo "Usage: gwt init <repo> [name]" >&2
return 1
}
local repo="$1"
local name="${2:-$(basename "$repo" .git)}"
git clone --bare "$repo" "$name" && cd "$name" || return 1
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git fetch origin
local default
default=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null)
default=${default#origin/}
: "${default:=main}"
mkdir -p trees
git worktree add "trees/$default" "$default"
cd "trees/$default"
}
_gwt_add() {
[[ -z "$1" ]] && {
echo "Usage: gwt add <branch> [dir]" >&2
return 1
}
local branch="$1"
local name="${2:-$1}"
local root
root=$(_gwt_root) || return 1
local dir="$root/trees/$name"
mkdir -p "$root/trees"
if git show-ref --verify --quiet "refs/heads/$branch"; then
git worktree add "$dir" "$branch"
elif git show-ref --verify --quiet "refs/remotes/origin/$branch"; then
git worktree add -b "$branch" "$dir" "origin/$branch"
else
git worktree add -b "$branch" "$dir"
fi && cd "$dir"
}
_gwt_fork() {
[[ -z "$1" ]] && {
echo "Usage: gwt fork <new-branch> [dir]" >&2
return 1
}
local new_branch="$1"
local name="${2:-$1}"
local root
root=$(_gwt_root) || return 1
local dir="$root/trees/$name"
mkdir -p "$root/trees"
git worktree add -b "$new_branch" "$dir" && cd "$dir"
}
_gwt_jump() {
command -v fzf >/dev/null || {
echo "fzf required" >&2
return 1
}
local root
root=$(_gwt_root) || return 1
local dir
dir=$(git worktree list | grep "/trees/" | fzf --height=40% --reverse | awk '{print $1}')
[[ -n "$dir" ]] && cd "$dir"
}
_gwt_rm() {
[[ -z "$1" ]] && {
echo "Usage: gwt rm <name>" >&2
return 1
}
local root
root=$(_gwt_root) || return 1
git worktree remove "$root/trees/$1"
}
_gwt_ls() {
local root
root=$(_gwt_root) || return 1
git --git-dir="$root" worktree list
}
_gwt_st() {
local root
root=$(_gwt_root) || return 1
for wt in "$root"/trees/*/; do
[[ -f "$wt/.git" ]] || continue
printf "\n\033[1m%s\033[0m\n" "$(basename "${wt%/}")"
git -C "$wt" status -sb
done
}
_gwt_help() {
cat <<'EOF'
Git Worktree Manager (bare repo workflow)
Usage: gwt <command> [args]
Commands:
init <repo> [name] Clone bare repo + setup structure
add <branch> [dir] Add worktree (existing branch or from origin)
fork <branch> [dir] Add worktree branched from current HEAD
jump fzf picker
rm <name> Remove worktree
ls List worktrees
st Status all
Aliases: a=add, f=fork, j=jump
Examples:
gwt init git@github.com:user/repo.git
gwt add feature-x # checkout existing branch
gwt fork spike-idea # new branch from current HEAD
gwt jump # switch worktrees
EOF
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment