#!/usr/bin/env bash # source: Jefromi on Stack Overflow -- https://stackoverflow.com/a/4157435 # modified by spwhitton to default to $branch@{u} at the suggestion of # orip on Stack Overflow # modified by spwhitton not to output a diff when the fast-forward # didn't change anything # modified by spwhitton to add trailing '--' to call to git-diff(1), # which avoids an error when there is a filename and branch with the # same name # modified by spwhitton to handle branches checked out in other worktrees _usage() { echo "Usage: git merge-ff []" 1>&2 exit 1 } _merge_ff() { branch="$1" commit="$2" branch_orig_hash="$(git show-ref -s --verify refs/heads/$branch 2> /dev/null)" if [ $? -ne 0 ]; then echo "Error: unknown branch $branch" 1>&2 _usage fi commit_orig_hash="$(git rev-parse --verify $commit 2> /dev/null)" if [ $? -ne 0 ]; then echo "Error: unknown revision $commit" 1>&2 _usage fi worktree=$(git worktree list --porcelain | perl -000 -wn \ -e'm#^branch refs/heads/'"$branch"'$#m && m#^worktree (.+)$#m && print $1') if [ -n "$worktree" ]; then git -C "$worktree" merge $quiet --ff-only "$commit" else if [ "$(git merge-base $branch_orig_hash $commit_orig_hash)" != "$branch_orig_hash" ]; then echo "Error: merging $commit into $branch would not be a fast-forward" 1>&2 exit 1 fi if [ "$commit_orig_hash" = "$branch_orig_hash" ]; then if [ -z $quiet ]; then echo "Already up-to-date." fi exit 0 fi echo "Updating ${branch_orig_hash:0:7}..${commit_orig_hash:0:7}" if git update-ref -m "merge $commit: Fast forward" "refs/heads/$branch" "$commit_orig_hash" "$branch_orig_hash"; then if [ -z $quiet ]; then echo "Fast forward" git diff --stat "$branch@{1}" "$branch" -- fi else echo "Error: fast forward using update-ref failed" 1>&2 fi fi } while getopts "q" opt; do case $opt in q ) quiet="-q";; * ) ;; esac done shift $((OPTIND-1)) case $# in 2 ) _merge_ff "$1" "$2";; 1 ) _merge_ff "$1" "${1}@{upstream}";; * ) _usage esac