Created
September 14, 2017 13:58
-
-
Save 0cjs/7c4ca55dadf3d55a1b4cdb147a6982bc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -o pipefail | |
. "$(git --exec-path)/git-sh-setup" | |
# | |
# Also see "$(git --exec-path)/git-filter-branch" for, e.g., a list of | |
# functions available in the commit filter. | |
# set_reflog_action | |
contains() { | |
local match="$1"; shift | |
local el | |
for el; do [[ $el == $match ]] && return 0; done | |
return 1 | |
} | |
default_author() { | |
local a_tree=$(git cat-file -p @ | sed -n -e 's/tree //p') | |
local a_commit=$(git commit-tree -m '' $a_tree </dev/null) | |
git cat-file -p $a_commit \ | |
| sed -n -e 's/ [0-9]* +[0-9]*$//' -e 's/author //p' | |
} | |
branches_with() { | |
[[ -n $1 || -z $2 ]] || die "INTERNAL ERROR: branches: bad args" | |
git branch --list --format='%(refname)' --contains "$1" | |
} | |
############################################################ | |
# Main | |
reviewer="$(default_author)" | |
branch= | |
dry_run=false | |
force=false | |
while true; do case "$1" in | |
-b|--branch) shift; branch="$1"; shift;; | |
-f|--force) shift; force=true;; | |
-n|--dry-run) shift; dry_run=true;; | |
-r|--reviewer) shift; reviewer="$1"; shift;; | |
*) break;; | |
esac; done | |
# Canonicalize ref name (HEAD if not specified) | |
ref="$(git rev-parse --symbolic-full-name --short ${branch:-@} 2>/dev/null)" | |
[[ -z $ref ]] && die "Unknown ref: $branch" | |
# Create list of individual commits (in abbreviated hash format) | |
commits=() | |
for i in "$@"; do | |
if [[ $i =~ \.\. ]]; then | |
commits+=($(git log --format=%h "$i")) | |
else | |
commits+=($(git log --format=%h -1 "$i")) | |
fi | |
done | |
#for i in "${commits[@]}"; do echo commit: $i; done | |
# Ensure all commits are on the given branch | |
for i in "${commits[@]}"; do | |
# XXX For some reason, `git-branch` says that `refs/heads/foo` doesn't | |
# contain a commit when `foo` contains it. We hack by removing the | |
# `refs/heads` prefix, but there must be a better/more reliable way.... | |
[[ -n $(git branch --contains "$i" "${ref#refs/heads/}") ]] \ | |
|| die "Branch $ref doesn't contain commit $i" | |
done | |
# Here it would be nice to figure out the earliest commit so we didn't | |
# have to rewrite the entire branch back to the beginning. It would also | |
# reduce the amount of output generated by progress mesages, which can | |
# be considerable. (There's no way to disable the progress messages, and | |
# if they're longer than a terminal line there are many, many lines of | |
# output due to `\n` going back to beginning of line instead of message.) | |
echo "Marking these commits on $ref as" | |
echo " Reviewed-by: $reviewer" | |
for i in "${commits[@]}"; do | |
git log -n 1 --format='%h %ae %s' "$i" | sed -e 's/@[^ ]*/@/' | |
done | |
$dry_run && exit 1 | |
$force || { | |
read -p 'OK? [y/N]' ok | |
[[ $ok =~ ^[Yy] ]] || die "Aborted" | |
} | |
echo | |
trailer_config="-c trailer.where=after \ | |
-c trailer.ifmissing=add -c trailer.ifexists=addIfDifferent \ | |
" # User may override trailer.separators (default `:`) if he likes. | |
# To avoid halting due to the existence of a `refs/original` entry | |
# from a previous `git filter-branch` we use `--force` to wipe it out | |
# (which wipes out its reflog, too). We compensate by ensuring a | |
# reflog is created for the branch we're filtering. | |
# | |
echo XXX rewriting "'$ref'" | |
commits="${commits[@]}" # convert to space separated due to quoting below | |
git -c core.logAllRefUpdates=always filter-branch --force \ | |
--msg-filter " | |
for id in $commits; do | |
[[ \$GIT_COMMIT =~ ^\$id ]] && { | |
git $trailer_config interpret-trailers \ | |
--trailer 'Reviewed-by: $reviewer' | |
exit | |
} | |
done | |
cat | |
" "$ref" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment