Skip to content

Instantly share code, notes, and snippets.

@tsibley
Created August 1, 2024 17:10
Show Gist options
  • Save tsibley/9bf6bcfeede69d07687f50697622b226 to your computer and use it in GitHub Desktop.
Save tsibley/9bf6bcfeede69d07687f50697622b226 to your computer and use it in GitHub Desktop.
#!/bin/bash
# usage: git diff-rebase
# git diff-rebase u[pstream]
# git diff-rebase <a> [<b>] [<branch>]
# git diff-rebase -h
#
# Display the differences in a branch after rebasing it.
#
# Immediately after a rebase, running this command with no arguments displays
# differences between the pre- and post-rebase versions of the current branch
# using "git range-diff". This is very handy to check that the result of the
# rebase you just performed matches your expectations.
#
# If the sole argument "u" or "upstream" is provided, the differences between
# the remote tracking branch and your local branch are displayed. This is
# handy when you've done several rebases in a row and want to compare your
# expectations to what you pushed previously.
#
# For advanced and uncommon use cases, up to three arguments may be provided to
# partially or fully specify the reflog entries to compare. The first two
# arguments, <a> and <b>, specify the branch reflog entries to compare and
# default to 1 and 0. The third argument, <branch>, specifies the branch name
# whose reflog to use, with HEAD allowed as an alias for the current branch.
# (Note that the current branch's reflog is distinct from HEAD's reflog
# normally.) All together, these three values identify the two reflog entries
# to compare in the form of <branch>@{<a>} and <branch>@{<b>}. Refer to the
# documentation of "git rev-parse", § "Specifying revisions" for an explanation
# of what these mean. The merge base is always assumed to be relative to
# master. Set diff-rebase.base-branch to use a different branch.
#
# For an explanation of the diff format that's output, refer to the
# documentation of "git range-diff".
#
# The DIFFOPTS environment variable may be set to pass extra options to "git
# range-diff".
#
set -euo pipefail
main() {
for arg; do
case "$arg" in
--help|-h)
usage
exit 0;;
esac
done
local branch="$(branch-name "${3:-HEAD}")"
local a="$branch@{${1:-1}}"
local b="$branch@{${2:-0}}"
exec git range-diff ${DIFFOPTS:-} \
"$(branch-merge-base $a)..$a" \
"$(branch-merge-base $b)..$b"
}
branch-name() {
case "$1" in
HEAD)
# Resolve HEAD to a branch name name to access its reflog. This is
# necessary because we don't want HEAD's reflog, which changes on
# each checkout.
git symbolic-ref --short HEAD;;
*)
# Ensure the passed ref is a parseable branch name
git rev-parse --revs-only --symbolic "$1" --;;
esac
}
branch-merge-base() {
git merge-base "$(git config --default master --get trs.diff.base)" "$1"
}
usage() {
local line
while read -r line; do
if [[ $line =~ ^#! ]]; then
continue
elif [[ $line =~ ^# ]]; then
line="${line/##/}"
line="${line/# /}"
echo "$line"
else
break
fi
done < "$0"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment