Last active
May 28, 2026 10:51
-
-
Save programaker/37cac1aaabce5a6c80777b290b8a1c6c to your computer and use it in GitHub Desktop.
Script to clone or init a repository in a git-worktree setup
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/zsh | |
| # Usage: | |
| # gitwt -c <git-uri> Clone an existing repo into a worktree setup | |
| # gitwt -n <project-name> Create a new project from scratch with worktree setup | |
| # gitwt -b <branch-name> [<base-branch>] Create a new worktree with a new branch (run from project root) | |
| # Optionally base the new branch on <base-branch>. Pass it exactly as you | |
| # want git to resolve it (e.g. 'develop' for the local branch, or | |
| # 'origin/develop' for the remote-tracking ref). If omitted, git's default | |
| # behavior applies (branch from HEAD). | |
| # gitwt <branch-name> Create a worktree for an existing branch (run from project root) | |
| # | |
| # Examples: | |
| # gitwt -c git@github.com:commercetools/the-repo-i-want-to-clone.git | |
| # gitwt -n my-new-project | |
| # gitwt -b my-feature-branch | |
| # gitwt -b my-feature-branch develop | |
| # gitwt -b my-feature-branch origin/develop | |
| # gitwt some-existing-branch | |
| set -euo pipefail | |
| function usage() { | |
| echo "Usage:" | |
| echo " gitwt -c <git-uri> Clone a repo into a worktree setup" | |
| echo " gitwt -n <project-name> Create a new project with worktree setup" | |
| echo " gitwt -b <branch-name> [<base-branch>] Create a new worktree with a new branch" | |
| echo " (optionally based on <base-branch>, passed as-is to git;" | |
| echo " if omitted, git branches from HEAD)" | |
| echo " gitwt <branch-name> Create a worktree for an existing branch" | |
| echo "" | |
| echo "Examples:" | |
| echo " gitwt -c git@github.com:org/repo.git" | |
| echo " gitwt -n my-new-project" | |
| echo " gitwt -b my-feature-branch" | |
| echo " gitwt -b my-feature-branch develop" | |
| echo " gitwt -b my-feature-branch origin/develop" | |
| echo " gitwt some-existing-branch" | |
| } | |
| function check_dir() { | |
| local name="$1" | |
| if [[ -d "$name" ]]; then | |
| echo "Error: directory '$name' already exists" | |
| exit 1 | |
| fi | |
| } | |
| function link_bare() { | |
| echo "gitdir: ./.bare" > .git | |
| git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" | |
| } | |
| function create_project() { | |
| local project_name="$1" | |
| local default_branch="main" | |
| local worktree_dir="${project_name}_${default_branch}" | |
| check_dir "$project_name" | |
| echo "Creating new worktree project '$project_name'..." | |
| mkdir "$project_name" | |
| cd "$project_name" | |
| git init --bare .bare | |
| link_bare | |
| git worktree add "$worktree_dir" -b "$default_branch" | |
| echo "" | |
| echo "Done! Your worktree project is ready:" | |
| echo " $project_name/" | |
| echo " .bare/ (git database)" | |
| echo " .git (pointer to .bare)" | |
| echo " $worktree_dir/ (worktree on $default_branch branch)" | |
| echo "" | |
| echo "Next steps:" | |
| echo " cd $project_name/$worktree_dir" | |
| echo " have fun!" | |
| } | |
| function clone_repo() { | |
| local uri="$1" | |
| # Extract repo name from URI | |
| # Handles both SSH (git@github.com:org/repo.git) and HTTPS (https://github.com/org/repo.git) | |
| local repo_name="${uri:t:r}" | |
| if [[ -z "$repo_name" ]]; then | |
| echo "Error: could not extract repository name from '$uri'" | |
| exit 1 | |
| fi | |
| check_dir "$repo_name" | |
| echo "Setting up bare worktree repo for '$repo_name'..." | |
| mkdir "$repo_name" | |
| cd "$repo_name" | |
| git clone --bare "$uri" .bare | |
| link_bare | |
| local default_branch=$(git -C .bare symbolic-ref --short HEAD) | |
| local worktree_dir="${repo_name}_${default_branch}" | |
| git worktree add "$worktree_dir" "$default_branch" | |
| git branch --set-upstream-to="origin/$default_branch" "$default_branch" | |
| echo "" | |
| echo "Done! Your worktree repo is ready:" | |
| echo " $repo_name/" | |
| echo " .bare/ (git database)" | |
| echo " .git (pointer to .bare)" | |
| echo " $worktree_dir/ (worktree on $default_branch branch)" | |
| echo "" | |
| echo "Next steps:" | |
| echo " cd $repo_name/$worktree_dir" | |
| echo " have fun!" | |
| } | |
| function create_branch_worktree() { | |
| local branch_name="$1" | |
| local base_branch="${2:-}" | |
| if [[ ! -d ".bare" ]]; then | |
| echo "Error: not inside a gitwt project (no .bare directory found)" | |
| exit 1 | |
| fi | |
| local worktree_dir="${branch_name}" | |
| check_dir "$worktree_dir" | |
| echo "Fetching origin..." | |
| git fetch origin | |
| if [[ -n "$base_branch" ]]; then | |
| echo "Creating worktree for branch '$branch_name' based on '$base_branch'..." | |
| git worktree add "$worktree_dir" -b "$branch_name" "$base_branch" | |
| else | |
| echo "Creating worktree for branch '$branch_name'..." | |
| git worktree add "$worktree_dir" -b "$branch_name" | |
| fi | |
| echo "" | |
| echo "Done! New worktree ready:" | |
| if [[ -n "$base_branch" ]]; then | |
| echo " $worktree_dir/ (worktree on $branch_name branch, based on $base_branch)" | |
| else | |
| echo " $worktree_dir/ (worktree on $branch_name branch)" | |
| fi | |
| } | |
| function checkout_branch_worktree() { | |
| local branch_name="$1" | |
| if [[ ! -d ".bare" ]]; then | |
| echo "Error: not inside a gitwt project (no .bare directory found)" | |
| exit 1 | |
| fi | |
| local worktree_dir="${branch_name}" | |
| check_dir "$worktree_dir" | |
| echo "Fetching origin..." | |
| git fetch origin | |
| echo "Creating worktree for existing branch '$branch_name'..." | |
| git worktree add "$worktree_dir" "$branch_name" | |
| echo "" | |
| echo "Done! New worktree ready:" | |
| echo " $worktree_dir/ (worktree on $branch_name branch)" | |
| } | |
| # --- Main --- | |
| if [[ $# -eq 2 && "$1" == "-b" ]]; then | |
| create_branch_worktree "$2" | |
| elif [[ $# -eq 3 && "$1" == "-b" ]]; then | |
| create_branch_worktree "$2" "$3" | |
| elif [[ $# -eq 2 && "$1" == "-n" ]]; then | |
| create_project "$2" | |
| elif [[ $# -eq 2 && "$1" == "-c" ]]; then | |
| clone_repo "$2" | |
| elif [[ $# -eq 1 && "$1" != -* ]]; then | |
| checkout_branch_worktree "$1" | |
| else | |
| usage | |
| exit 1 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment