Skip to content

Instantly share code, notes, and snippets.

@nicknisi
Created January 27, 2022 12:44
Show Gist options
  • Save nicknisi/a26f148611517e3d998eb456ac57efff to your computer and use it in GitHub Desktop.
Save nicknisi/a26f148611517e3d998eb456ac57efff to your computer and use it in GitHub Desktop.
Create a new worktree, install dependencies, and run an initial build
#!/usr/bin/env bash
# This script should help facilitate setting up a new worktree, including:
# - creating a new worktree
# - installing dependencies
# - creating a new branch
set -Eeuo pipefail
trap cleanup SIGINT SIGTERM ERR EXIT
# shellcheck disable=SC2034
script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd -P)
usage() {
cat <<EOF
Usage: $(basename "${BASH_SOURCE[0]}") [-h] [-v] [-f] [-b] [-B] [-p] [-N] <path>
Script the creation of a new worktree.
Available options:
-h, --help Print this help and exit
-v, --verbose Print script debug info
-b, --branch The branch to create
-B, --base The branch to use as the base for the new worktree (default: develop)
-p, --prefix The prefix to apply to the branch name (default: $(git config github.user)/)
-N, --no-create-upstream Do not create an upstream branch
This script performs the following steps:
1. Create a new worktree, based off the base branch (default: develop)
2. Create a new upstream branch to track the work
2. Install dependencies
3. Run a build
EOF
exit
}
cleanup() {
trap - SIGINT SIGTERM ERR EXIT
tput cnorm # enable cursor
# script cleanup here
}
setup_colors() {
if [[ -t 2 ]] && [[ -z "${NO_COLOR-}" ]] && [[ "${TERM-}" != "dumb" ]]; then
# shellcheck disable=SC2034
NOFORMAT='\033[0m' GRAY='\033[0;90m' RED='\033[0;31m' GREEN='\033[0;32m' ORANGE='\033[0;33m' BLUE='\033[0;34m' PURPLE='\033[0;35m' CYAN='\033[0;36m' YELLOW='\033[1;33m'
else
# shellcheck disable=SC2034
NOFORMAT='' GRAY='' RED='' GREEN='' ORANGE='' BLUE='' PURPLE='' CYAN='' YELLOW=''
fi
}
msg() {
echo >&2 -e "${1-}"
}
# log() {
# echo >&2 -ne "${1-}"
# }
info() {
msg "${GRAY}[INFO]${NOFORMAT} ${1-}"
}
die() {
local msg=$1
local code=${2-1} # default exit status 1
msg "$msg"
exit "$code"
}
function spinner() {
# make sure we use non-unicode character type locale
# (that way it works for any locale as long as the font supports the characters)
local LC_CTYPE=C
local pid=$1 # Process Id of the previous running command
local spin='⣾⣽⣻⢿⡿⣟⣯⣷'
local charwidth=3
local i=0
tput civis # cursor invisible
while kill -0 "$pid" 2>/dev/null; do
local i=$(((i + charwidth) % ${#spin}))
printf >&2 "%s" "${spin:$i:$charwidth}"
printf >&2 "\b"
sleep .1
done
tput cnorm
wait "$pid" # capture exit code
return $?
}
run_command() {
local message=$1
shift
echo >&2 -ne "$message "
"$@" &>/dev/null &
spinner $!
# shellcheck disable=SC2181
if [ $? -eq 0 ]; then
echo >&2 -e " ${GREEN}Done.${NOFORMAT}"
else
echo >&2 -e " ${RED}FAILED.${NOFORMAT}"
exit 1
fi
}
parse_params() {
# default values of variables set from params
create_upstream=1
prefix="$(git config github.user)/"
base='origin/develop'
branch=''
while :; do
case "${1-}" in
-h | --help) usage ;;
-v | --verbose) set -x ;;
--no-color) NO_COLOR=1 ;;
-N | --no-create-upstream) create_upstream=0 ;;
-b | --branch)
branch="$2"
shift
;;
-B | --base)
base="${2-}"
shift
;;
-?*) die "Unknown option: $1" ;;
*) break ;;
esac
shift
done
args=("$@")
# check required params and arguments
# [[ -z "${param-}" ]] && die "Missing required parameter: param"
[[ ${#args[@]} -eq 0 ]] && die "Missing script arguments"
# if a branch was not specified, generate one based on the prefix and folder name
if [[ -z "$branch" ]]; then
branch="${prefix}${args[0]}"
fi
worktree="${args[0]}"
return 0
}
parse_params "$@"
setup_colors
update_remote() {
local branch="$1"
# do nothing if create_upstream is disabled
[ $create_upstream -eq 0 ] && return 0
if [[ -z "$(git ls-remote --heads origin "$branch")" ]]; then
# create remote branch
msg "${GRAY}Branch '$branch' does not exist on remote. Creating."
run_command "Creating remote branch ${branch}..." git push -u origin "$branch"
else
msg "${GRAY}Branch '$branch' exists. Setting upstream."
run_command "Setting upstream branch to 'origin/$branch'" git branch --set-upstream-to="origin/$branch"
fi
}
# check if branch already exists
if [[ -n "$(git branch --list "$branch")" ]]; then
run_command "Generating new worktree from existing branch: $branch" git worktree add "$worktree" "$branch"
else
run_command "Generating new worktree: $worktree" git worktree add -b "$branch" "$worktree" "$base"
fi
msg "${GRAY}Moving into worktree: $worktree${NOFORMAT}"
cd "$worktree"
update_remote "$branch"
run_command "Setting Node version" fnm use < .nvmrc
run_command "Installing dependencies" npm --no-progress --silent install
run_command "Building App" npm run --silent build
msg "${GREEN}Success.${NOFORMAT}"
@ayoubelmhamdi
Copy link

The script accepts the following arguments and options, with all possible combinations based on the provided logic. Below is a concise breakdown of the possible ways to use the script, including required arguments and optional flags.

Script Usage

./script.sh [-h] [-v] [-b <branch>] [-B <base>] [-p <prefix>] [-N] <path>

Required Argument

  • <path>: The path for the new worktree (mandatory). Used as part of the branch name if -b is not specified.

Optional Flags and Parameters

  • -h, --help: Print help and exit.
  • -v, --verbose: Enable debug output.
  • -b <branch>, --branch <branch>: Specify the branch name (overrides default branch name: <prefix><path>).
  • -B <base>: Specify the base branch (default: origin/develop).
  • -N, --no-create-upstream: Disable creating an upstream branch.
  • --no-color: Disable colors output (not listed in usage but supported).

Default Values

  • Prefix: $(git config github.user)/ (used if -b is not provided).
  • Storage branch: masterorigin/develop.
  • Branch name: If -b is not specified, generated as <prefix><path>.

All Possible Combinations

The script requires at least <path>. Optional flags can be combined in any order, except -h (which exits immediately). Below are the valid combinations, grouped by key scenarios:

1. Minimal Usage

  • ./script.sh <path>
    • Creates worktree at <path>, branch named <prefix><path>, based on origin/develop, with upstream branch creation.

2. With Specific Branch (-b)

  • ./script.sh -b <branch> <path>
    • Creates worktree at <path>, uses specified <branch>, based on origin/develop, with upstream branch creation.
  • ./script.sh -b <branch> -B <base> <path>
    • Same as above, but uses specified <base> instead of origin/develop.
  • ./script.sh -b <branch> -N <path>
    • Same as -b <branch> <path>, but no upstream branch creation.
  • ./script.sh -b <branch> -B <base> -N <path>
    • Combines specified <branch>, <base>, and no upstream creation.

3. With Custom Base Branch (-B)

  • ./script.sh -B <base> <path>
    • Creates worktree at <path>, branch named <prefix><path>, based on specified <base>, with upstream branch creation.
  • ./script.sh -B <base> -N <path>
    • Same as above, but no upstream branch creation.

4. Without Upstream Branch Creation (-N)

  • ./script.sh -N <path>
    • Creates worktree at <path>, branch named <prefix><path>, based on origin/develop, no upstream branch creation.

5. With Verbose Output (-v)

  • ./script.sh -v <path>
    • Same as minimal usage, but with debug output enabled.
  • Can be combined with any other flags, e.g.:
    • ./script.sh -v -b <branch> <path>
    • ./script.sh -v -B <base> <path>
    • ./script.sh -v -N <path>
    • ./script.sh -v -b <branch> -B <base> -N <path>

6. Without Color Output (--no-color)

  • ./script.sh --no-color <path>
    • Same as minimal usage, but disables colors output.
  • Can be combined with any other flags, e.g.:
    • ./script.sh --no-color -b <branch> <path>
    • ./script.sh --no-color -B <base> <path>
    • ./script.sh --no-color -N <path>
    • ./script.sh --no-color -v -b <branch> -B <base> -N <path>

7. Help Flag (-h)

  • ./script.sh -h or ./script.sh --help
    • Prints help message and exits. No other arguments or flags are processed.

Example Combinations

  • ./script.sh my-worktree
    • Worktree: my-worktree, Branch: <github.user>/my-worktree, Base: origin/develop, Upstream: Yes
  • ./script.sh -b feature/new-thing my-worktree
    • Worktree: my-worktree, Branch: feature/new-thing, Base: origin/develop, Upstream: Yes
  • ./script.sh -B main -N my-worktree
    • Worktree: my-worktree, Branch: <github.user>/my-worktree, Base: main, Upstream: No
  • ./script.sh -v -b bugfix/issue-123 -B release/v1.0 -N my-worktree
    • Worktree: my-worktree, Branch: bugfix/issue-123, Base: release/v1.0, Upstream: No, Verbose: Yes
  • ./script.sh --no-color -b test-branch my-worktree
    • Worktree: my-worktree, Branch: test-branch, Base: origin/develop, Upstream: Yes, No colors

Notes

  • The -p flag is listed in the usage but not implemented in the script, so it’s ignored.
  • Invalid flags (e.g., -x) cause the script to exit with an error.
  • Missing <path> results in an error.
  • Flags can be provided in any order, except <path> must be last.
  • The script assumes git, fnm, and npm are available in the environment.

This covers all valid ways to invoke the script based on its logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment