#!/bin/sh
set -eu

#
# Inspired by Magit's super useful `magit-branch-spinoff` command.
# See also https://magit.vc/manual/magit/Branch-Commands.html
#

usage () {
    cat <<'EOF'
usage: git spinoff [-h] <new-name> [<base>]

Creates and checks out a new branch starting at and tracking the
current branch.  That branch in turn is reset to the last commit it
shares with its upstream.  If the current branch has no upstream or no
unpushed commits, then the new branch is created anyway and the
previously current branch is not touched.

This is useful to create a feature branch after work has already
began on the old branch (likely but not necessarily "main").

Options:
-h    Show this help
EOF
}

while getopts h flag; do
    case "$flag" in
        h) usage; exit 0;;
    esac
done
shift $(($OPTIND - 1))

if [ $# -lt 1 ] || [ $# -gt 2 ]; then
  usage >&2
  exit 2
fi

new_name="$1"
rawbase="${2:-}"
if [ -z "$rawbase" ]; then
    base="$(git current-branch)"
else
    base="$rawbase"
fi

base_sha="$(git sha -s "$base")"

#
# NOTE:
# The flag -B is the transactional equivalent of
#     $ git branch -f <branch> [<start point>]
#     $ git checkout <branch>
#
git checkout -q --track -B "$new_name" "$base"

rtb="$(git remote-tracking-branch "$base")"
if [ -n "$rtb" ]; then
    merge_base="$(git merge-base "$base" "$rtb")"
    git branch -vf "$base" "$merge_base"
fi

if [ "$(git sha -s "$base")" != "$base_sha" ]; then
    echo "$base reset to $(git sha -s "$base") (was $base_sha)"
else
    echo "$base not touched"
fi
