|
#!/bin/sh |
|
# git-rewrite-author.sh |
|
# |
|
# Rewrite git-commit author's Name/EmailAddress. |
|
# |
|
# Based on previous versions of this tool This version runs in POSIX compliant |
|
# shell and .. IMHO .. cleans up a large portion of the filter logic and the |
|
# core syntax such that is is readable and not full of back-slash escape hell. |
|
# |
|
# Other versions: |
|
# - https://gist.github.com/Hackl0us/490f56dbc135b2fae47d8e2b97c9d8b3 |
|
# - https://gist.github.com/octocat/0831f3fbd83ac4d46451 |
|
# - https://gist.github.com/frz-dev/adf8c2c7275da1369e0cc340feda0ba0 |
|
# - https://gist.github.com/octocat/0831f3fbd83ac4d46451#gistcomment-2178506 |
|
|
|
error() { echo "error: $*"; } |
|
die() { echo "error: $*"; exit 1; } |
|
usage() { |
|
if test "$#" -gt '0'; then |
|
error "error: $*" |
|
echo "try '${0} --help'" >&2 |
|
exit 1 |
|
fi |
|
|
|
sed -e 's/^ //' << END_OF_USAGE |
|
usage: ${0} [<options>] [--] [<git filter options>] |
|
|
|
Options: |
|
-n, --cur-name "First Last" Match commits with this name |
|
-N, --new-name "First Last" New name to write to commits |
|
-e, --cur-email EMAIL Match commits with this email address |
|
-E, --new-email EMAIL New email address write to commits |
|
-c, --current Use current git configured user/email when updating commits |
|
--dry-run Do not actually make any changes |
|
-x, --trace Enable execution tracing |
|
-h, --help Display this help |
|
|
|
Notes: |
|
- For all matches, both author/committer name and email will be |
|
replaced (if both are provided) |
|
- You can pass the git-filter option --force to foricbly overwrite |
|
backups if you need to run the command multiple times. |
|
- To push the changes use the following command: |
|
git push --force --tags origin 'refs/heads/*'" |
|
END_OF_USAGE |
|
|
|
# requests for help are not an error |
|
exit 0 |
|
} |
|
|
|
## gen_filter |
|
# $1: cur_name |
|
# $2: cur_email |
|
# $3: new_name |
|
# $4: new_email |
|
gen_filter() { |
|
cat<<END_OF_FILTER |
|
if [ "\${GIT_AUTHOR_NAME}" = "${1}" ] || [ "\${GIT_AUTHOR_EMAIL}" = "${2}" ]; then |
|
test -z "${3}" || export GIT_AUTHOR_NAME="${3}" |
|
test -z "${4}" || export GIT_AUTHOR_EMAIL="${4}" |
|
fi |
|
END_OF_FILTER |
|
} |
|
|
|
|
|
## |
|
# parse args |
|
current='false' |
|
dry_run='false' |
|
while test "$#" -gt '0'; do |
|
case "$1" in |
|
(-h|-help|--help) |
|
usage;; |
|
(-n|--cur-name) |
|
cur_name="$2" |
|
shift;; |
|
(-N|--new-name) |
|
new_name="$2" |
|
shift;; |
|
(-e|--cur-email) |
|
cur_email="$2" |
|
shift;; |
|
(-E|--new-email) |
|
new_email="$2" |
|
shift;; |
|
(-c|--current) |
|
current='true';; |
|
(--dry-run) |
|
dry_run='true';; |
|
(-x|--trace) |
|
set -x;; |
|
|
|
# POSIX CLI handling |
|
(--) shift; break;; |
|
(-*) usage "unknown option '$1'";; |
|
(*) break;; |
|
esac |
|
shift |
|
done |
|
|
|
|
|
## |
|
# Validate our inputs |
|
if ${current}; then |
|
new_email="$(git config user.email)" |
|
new_name="$(git config user.name)" |
|
fi |
|
|
|
if test -z "${cur_name}" && test -z "${cur_email}"; then |
|
usage 'must specify a current name or email address to match' |
|
fi |
|
|
|
if test -z "${new_name}" && test -z "${new_email}"; then |
|
usage 'must specify a new name or email address to write' |
|
fi |
|
|
|
## |
|
# Just do it |
|
if "${dry_run}"; then |
|
echo git filter-branch \ |
|
--env-filter "$(gen_filter "${cur_name}" "${cur_email}" "${new_name}" "${new_email}")" \ |
|
"$@" --tag-name-filter cat -- --branches --tags |
|
else |
|
exec git filter-branch \ |
|
--env-filter "$(gen_filter "${cur_name}" "${cur_email}" "${new_name}" "${new_email}")" \ |
|
"$@" --tag-name-filter cat -- --branches --tags |
|
fi |