Instantly share code, notes, and snippets.
Last active
February 19, 2017 14:43
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save mwatts15/cb528a081e4f9f4679c203e598e26093 to your computer and use it in GitHub Desktop.
A script for removing author names and email addresses from git commit history
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
#!/bin/sh | |
# A script for removing authors from git history and file contents | |
REPLACE_DOMAIN=${REPLACE_DOMAIN:-example.com} | |
TEMPDIR= | |
interactive= | |
restore_ref () { | |
if [ -f orig-ref ] ; then | |
orig=$(git rev-list --max-count=1 HEAD) | |
echo $orig > rewrite-ref | |
git reset --hard $(cat orig-ref) | |
rm orig-ref | |
else | |
echo No refs to restore >&2 | |
fi | |
} | |
rewrite_author () { | |
if [ $TEMPDIR ] ; then | |
temppart="-d $TEMPDIR" | |
fi | |
export OLD_EMAIL="${1}" | |
export OLD_NAME="${2}" | |
export CORRECT_NAME="${3}" | |
export CORRECT_EMAIL="${3}@${REPLACE_DOMAIN}" | |
git filter-branch $temppart -f --env-filter ' | |
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" -a "$GIT_COMMITTER_NAME" = "$OLD_NAME" ] ; then | |
export GIT_COMMITTER_NAME="$CORRECT_NAME" | |
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL" | |
fi | |
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" -a "$GIT_AUTHOR_NAME" = "$OLD_NAME" ] ; then | |
export GIT_AUTHOR_NAME="$CORRECT_NAME" | |
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL" | |
fi | |
' --tag-name-filter 'sed -r "s/^(export-)?/export-/"' -- --branches --tags | |
} | |
get_authors () { | |
i=0 | |
git log --format="format:%an:%ae" | sort -u | while read author; do | |
printf "%s:%04d\n" "$author" $i | |
i=$((i + 1)) | |
done | |
} | |
sanitize_author_names () { | |
author_map=$(readlink -f author-map) | |
if [ $TEMPDIR ] ; then | |
temppart="-d $TEMPDIR" | |
fi | |
if [ $FILE_EXCLUDES ] ; then | |
excludespart='-and -not -path "'$FILE_EXCLUDES'"' | |
fi | |
git filter-branch $temppart -f --tree-filter ' | |
while IFS=":" read old_name old_email new; do | |
find . -not -path "./.git*" '"$excludespart"' -type f -print0 \ | |
| xargs --null sed -i -e "s/\b$old_name\b/$new/" -e "s/\b$old_email\b/$new/" | |
done < '$author_map' | |
' | |
} | |
ensure_author_map () { | |
if [ -f author-map ] ; then | |
echo 'There is already an author=>id map in author-map.' | |
if [ $interactive ] ; then | |
echo -n 'Use(0), replace(1), or exit(2)? ' | |
read AUTHOR_MAP_HANDLING | |
fi | |
case $AUTHOR_MAP_HANDLING in | |
1|replace) | |
echo 'Replacing author-map' | |
get_authors > author-map | |
;; | |
2|exit) | |
exit 3 | |
;; | |
*) | |
echo 'Using existing author-map' | |
;; | |
esac | |
else | |
get_authors > author-map | |
fi | |
} | |
rewrite () { | |
orig=$(git rev-list --max-count=1 HEAD) | |
echo $orig > orig-ref | |
#while IFS=':' read old_name old_email new; do | |
#echo "$old_email $new" | |
#rewrite_author $old_email "$old_name" $new | |
#done < author-map | |
sanitize_author_names "$old_name" "$old_name" $new | |
git diff $orig | |
} | |
while getopts 'friga:x:d:' opt ; do | |
case $opt in | |
f) | |
force=1 | |
;; | |
r) | |
restore=1 | |
;; | |
i) | |
interactive=1 | |
;; | |
g) | |
just_gen_map=1 | |
;; | |
a) | |
AUTHOR_MAP_HANDLING=$OPTARG | |
;; | |
d) | |
TEMPDIR=$OPTARG | |
;; | |
x) | |
FILE_EXCLUDES=$OPTARG | |
;; | |
esac | |
done | |
shift $((OPTIND-1)) | |
if [ $restore ] ; then | |
restore_ref | |
else | |
ensure_author_map | |
if [ $just_gen_map ] ; then | |
exit 0 | |
fi | |
if [ ! $force ] ; then | |
if [ -f orig-ref ] ; then | |
echo "An original ref already exists. Delete it to continue" >&2 | |
exit 2 | |
fi | |
fi | |
rewrite | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment