#!/usr/bin/env bash # # wt-new.sh — start a branch in its own git worktree. # # WHY: every branch is developed in an isolated worktree, never by switching # the primary checkout (two shells in one checkout is how you clobber work). # This creates the branch off an up-to-date `main` and a sibling worktree # named to match the repo's existing convention: # # /-worktree- # e.g. feat/clause-concept-hints -> ../rdbms-playground-worktree-clause-concept-hints # # USAGE # scripts/wt-new.sh # scripts/wt-new.sh feat/clause-concept-hints # # Prints the new worktree path; cd there to start working. set -euo pipefail log() { printf ' wt-new: %s\n' "$*" >&2; } die() { printf 'wt-new: ERROR: %s\n' "$*" >&2; exit 1; } [ $# -eq 1 ] || die "usage: wt-new.sh (e.g. feat/my-thing)" branch="$1" # Conventional prefixes keep branch names aligned with commit types. case "$branch" in feat/*|fix/*|docs/*|chore/*|refactor/*|test/*|ci/*) : ;; *) die "branch should start with feat/ fix/ docs/ chore/ refactor/ test/ ci/ (got: $branch)" ;; esac git rev-parse --git-dir >/dev/null 2>&1 || die "not inside a git repo" # Sibling-of-the-primary-checkout location, matching existing worktrees. main_wt="$(git worktree list --porcelain | awk '/^worktree /{print $2; exit}')" parent="$(dirname "$main_wt")" repo="$(basename "$main_wt")" seg="${branch##*/}" target="$parent/${repo}-worktree-${seg}" [ -e "$target" ] && die "worktree path already exists: $target" git show-ref --verify --quiet "refs/heads/$branch" \ && die "branch already exists: $branch (use 'git worktree add' to attach a worktree to it)" log "fetching origin/main" git fetch --quiet origin main || die "git fetch origin main failed" log "creating branch '$branch' + worktree at $target" # `--no-track`: branch off origin/main for a fresh base, but DON'T inherit # origin/main as the upstream. Without this, branching off a remote-tracking # ref makes git set the new branch's upstream to origin/main, so a later bare # `git push` fails with a name-mismatch and suggests the dangerous # `git push origin HEAD:main`. With no upstream, the first `git push -u origin # ` sets the correct one. git worktree add --quiet --no-track -b "$branch" "$target" origin/main \ || die "git worktree add failed" log "ready — cd into it:" echo "$target"