otoolsを大体1年越しに使い始める俺、git-wtを使い始める

いままでworktree、よく開発するブランチは xxx-a,xxx-b,xxx-c のように3つくらい作っておいてそこで、pecoでdirectory移動して使っていたのだが、どのブランチをなににチェックアウトしてるのかを覚えておくのがだるすぎて、ようやくzshrc書いた。

# -------------------------------------
# git worktree
# -------------------------------------
export WORKTREE_BASE="${HOME}/worktrees"

function peco-worktree() {
    if [[ ! -d "$WORKTREE_BASE" ]]; then
        zle clear-screen
        return 0
    fi
    local selected
    selected=$(
        find "$WORKTREE_BASE" -mindepth 2 -maxdepth 2 -type d 2>/dev/null \
            | awk -F'/' -v OFS='\t' '{ print $(NF-1) "/" $NF, $0 }' \
            | column -t -s $'\t' \
            | peco --query "$LBUFFER"
    )
    if [[ -n "$selected" ]]; then
        local target_path
        target_path=$(echo "$selected" | awk '{print $NF}')
        BUFFER="cd ${target_path}"
        zle accept-line
    fi
    zle clear-screen
}
zle -N peco-worktree
bindkey '^w' peco-worktree

function cw() {
    if [[ $# -lt 1 ]]; then
        echo "Usage: cw <worktree-name>"
        return 1
    fi
    local name="$1"
    local repo_root
    repo_root=$(git rev-parse --show-toplevel 2>/dev/null)
    if [[ -z "$repo_root" ]]; then
        echo "Not in a git repository"
        return 1
    fi
    local repo_name
    repo_name=$(basename "$repo_root")
    local worktree_path="${WORKTREE_BASE}/${repo_name}/${name}"

    if [[ ! -d "$worktree_path" ]]; then
        mkdir -p "${WORKTREE_BASE}/${repo_name}"
        git -C "$repo_root" fetch origin "$name" --quiet 2>/dev/null
        if git -C "$repo_root" show-ref --verify --quiet "refs/heads/${name}"; then
            git -C "$repo_root" worktree add "$worktree_path" "$name" || return 1
        elif git -C "$repo_root" show-ref --verify --quiet "refs/remotes/origin/${name}"; then
            git -C "$repo_root" worktree add -b "$name" "$worktree_path" "origin/${name}" || return 1
        else
            local base
            base=$(git -C "$repo_root" for-each-ref --format='%(refname:short)' refs/heads refs/remotes \
                | grep -v '/HEAD$' \
                | peco --prompt "base for ${name}> ")
            if [[ -z "$base" ]]; then
                echo "base branch not selected"
                return 1
            fi
            git -C "$repo_root" worktree add -b "$name" "$worktree_path" "$base" || return 1
        fi
    fi

    cd "$worktree_path" || return 1
    [[ -n "$TMUX" ]] && tmux rename-window "$name"
    c
}

function cwc() {
    if [[ ! -d "$WORKTREE_BASE" ]]; then
        return 0
    fi
    local now threshold removed
    now=$(date +%s)
    threshold=$((30 * 86400))
    removed=0

    while IFS= read -r wt; do
        [[ -d "$wt" ]] || continue
        local last_commit last_mtime newest
        last_commit=$(git -C "$wt" log -1 --format=%ct 2>/dev/null || echo 0)
        last_mtime=$(stat -f %m "$wt" 2>/dev/null || echo 0)
        newest=$last_commit
        (( last_mtime > newest )) && newest=$last_mtime
        (( newest == 0 )) && continue

        if (( now - newest > threshold )); then
            local days=$(( (now - newest) / 86400 ))
            echo "Removing (last touched ${days}d ago): $wt"
            local main_wt
            main_wt=$(git -C "$wt" worktree list --porcelain 2>/dev/null | awk '/^worktree / { print $2; exit }')
            if [[ -n "$main_wt" && "$main_wt" != "$wt" ]]; then
                git -C "$main_wt" worktree remove --force "$wt" 2>/dev/null || rm -rf "$wt"
            else
                rm -rf "$wt"
            fi
            removed=$((removed + 1))
        fi
    done < <(find "$WORKTREE_BASE" -mindepth 2 -maxdepth 2 -type d 2>/dev/null)

    find "$WORKTREE_BASE" -mindepth 1 -maxdepth 1 -type d -empty -delete 2>/dev/null
    echo "Removed $removed stale worktree(s)"
}

作ったショートカット

  1. cw <branch_name> って打つと、base branchを何にするかの選択がpecoで選択できて、enter押すとalias c=claude code xxx な感じでclaude codeを起動して、tmuxのwindow nameをbranch nameにする。
  2. cwc って打つと1ヶ月使ってないwork treeを消す
  3. ctrl + w って打つと、worktreeの一覧が出てpecoでインクリメンタルサーチして移動できる。

とりあえず1時間くらいしか使ってないけど、便利すぎて失職寸前ですね!!!!!!!!!!!!!1