#!/usr/bin/env bash SQUASH_MSG= for arg in "$@"; do case "$arg" in --squash-msg) SQUASH_MSG=1 ;; *) # set the argument back set -- "$@" "$arg" ;; esac shift done src="$1" msg="$2" if [[ -n "$msg" ]] && [[ -n "$SQUASH_MSG" ]]; then >&2 echo "When commit message is given, --squash-msg is not allowed." exit 1 fi is_branch() { git show-ref --verify --quiet "refs/heads/$src" } is_commit_reference() { git rev-parse --verify --quiet "$src" > /dev/null 2>&1 } is_on_current_branch() { local commit_sha commit_sha=$(git rev-parse "$src") git rev-list HEAD | grep -q -- "$commit_sha" } commit_if_msg_provided() { if test -n "$msg"; then git commit -a -m "$msg" fi } prompt_continuation_if_squashing_default_branch() { if [[ $src == $(git_extra_default_branch) ]]; then read -p "Warning: squashing '$src'! Continue [y/N]? " -r if ! [[ $REPLY =~ ^[Yy]$ ]]; then echo "Exiting" exit 1 fi fi } squash_branch() { prompt_continuation_if_squashing_default_branch if [ -n "$SQUASH_MSG" ]; then base=$(git merge-base "$src" @) msg=$(git log "$base".."$src" --format="%s%n%n%b" --no-merges --reverse) fi git merge --squash "$src" || exit 1 # quits if `git merge` fails commit_if_msg_provided } squash_current_branch() { if [ -n "$SQUASH_MSG" ]; then msg=$(git log "$src"..@ --format="%s%n%n%b" --no-merges --reverse) fi git reset --soft "$src" || exit 1 # quits if `git reset` fails commit_if_msg_provided } if is_branch; then squash_branch elif is_commit_reference && is_on_current_branch; then squash_current_branch else echo "Source branch or commit reference required." 1>&2 && exit 1 fi