Skip to content

Instantly share code, notes, and snippets.

@Duologic
Last active February 19, 2026 11:53
Show Gist options
  • Select an option

  • Save Duologic/29725b14bc9ef397366e32020d3423ce to your computer and use it in GitHub Desktop.

Select an option

Save Duologic/29725b14bc9ef397366e32020d3423ce to your computer and use it in GitHub Desktop.
scripts to manage worktrees
#!/usr/bin/env bash
set -euo pipefail
DIR="/home/duologic/git/$1"
MAIN="${2:-main}"
mkdir -p "$DIR"
gh repo clone $1 "$DIR" -- --bare --depth 100
cd "$DIR"
git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git worktree add wt/$MAIN $MAIN
#!/usr/bin/env bash
# Parse command line arguments
STATE_FILTER="MERGED"
while [[ $# -gt 0 ]]; do
case $1 in
-s|--state)
STATE_FILTER="$2"
shift 2
;;
*)
echo "Usage: $0 [-s|--state STATE]"
echo " STATE: PR state to filter (default: MERGED, use empty string \"\" to match all)"
exit 1
;;
esac
done
worktrees=$(git worktree list |
grep -v '\[master\]' |
grep -v '\[main\]' |
grep -v '\(bare\)' |
awk -F' ' '{print $1}')
for wt in $worktrees; do
state=$(
cd $wt
gh pr view --json state | jq .state
)
if [[ -n "$STATE_FILTER" && $state != "\"$STATE_FILTER\"" ]]; then
continue
fi
# Set default based on state
if [[ $state == '"MERGED"' ]]; then
echo -n "Remove worktree '$wt' ($state)? (Y/n) "
read -r remove
# Default to yes for merged PRs
if [[ -z "$remove" ]]; then
remove='y'
fi
else
echo -n "Remove worktree '$wt' ($state)? (y/N) "
read -r remove
fi
clean=$(git -C "$wt" status --porcelain)
has_submodules=$(git -C "$wt" submodule status 2>/dev/null)
if [ "$remove" = 'y' ] && { [ -n "$clean" ] || [ -n "$has_submodules" ]; }; then
if [ -n "$clean" ]; then
echo "Worktree '$wt' not clean:"
git -C "$wt" status
fi
if [ -n "$has_submodules" ]; then
echo "Worktree '$wt' contains submodules:"
git -C "$wt" submodule status
fi
echo -n "Force remove? (y/N) "
read -r force_remove
if [ "$force_remove" = 'y' ]; then
remove='force'
fi
fi
if [ "$remove" = 'y' ]; then
echo "Removing '$wt'"
git worktree remove "$wt"
echo
elif [ "$remove" = 'force' ]; then
echo "Force removing '$wt'"
git worktree remove --force "$wt"
echo
fi
done
#!/usr/bin/env bash
worktrees=$(git worktree list \
| grep -v '\[master\]' \
| grep -v '\[main\]' \
| grep -v '\(bare\)' \
| awk -F' ' '{print $1}')
for wt in $worktrees;
do
state=$(cd $wt; gh pr view --json state 2> /dev/null)
state=$(echo $state | jq .state)
echo "($state) $(realpath -m --relative-to=$PWD $wt)"
done | column -t
#!/usr/bin/env bash
# call this from tmux bind-key: `bind-key y display-popup -E -T " wtwindow " "wtwindow"`
set -euo pipefail
if [ "$#" != 1 ]; then
GITDIRS=$(fd --glob --type d -H 'wt' $HOME/git)
PROJ=$(printf "$GITDIRS" | sed 's;'$HOME'/git/;;' | sed 's/\/\.git\///' | fzf)
PROJ="$HOME/git/$PROJ"
else
if stat "$1" >/dev/null; then
PROJ="$1"
elif stat "$HOME/git/$1" >/dev/null; then
PROJ="$HOME/git/$1"
else
echo "$1 not found"
exit 1
fi
fi
NAME="$(basename "${PROJ:0:-3}")"
tmux new-window -c "$PROJ" -n "$NAME"
sleep 1
tmux split-window -c "$PROJ" -t "$NAME" -h
tmux split-window -c "$PROJ" -t "$NAME"
tmux send-keys -t 2 "watch -n 30 'git wtlist'"
tmux send-keys -t 2 Enter
tmux select-pane -t 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment