In this little post I am going to show you why you sometimes need to rewrite the author or committer history, how you do it and where it will not work as expected.
- Git like a pro
- Sort git tags by date
- Rewrite author history
TL;DR
The complete source including command-generation can be found at github:
cytopia/git-rewrite-author
Why would I rewrite the git author history?
First things first, why would you ever want to rewrite the git author history? Think of the following scenario:
You are going to do a very urgent fix directly on the server deployed git repository. It seems to work fine and you commit it to the local repository and push it to remote. But wait… You totally forgot that you acted as root and when you issue a git log
it will show the following:
commit a0925c315107fcdcfb7a3b2dcd435995c8216ad2
Author: root <root@localhost>
Date: Sat Oct 10 21:39:43 2015 +0200
fixed xss on index.php
Damn’ that was a mistake. You should have taken the time and have done it on your local machine, pushed to remote and checked out on the server as your seniors always told you. Don’t worry, this can be fixed.
Rewriting the author history
This time you better do it locally. Make sure your local repository is up to date with the remote and quickly list all git authors:
$ git log --pretty=full | grep -E '(Author|Commit): (.*)$' | sed 's/Author: //g' | sed 's/Commit: //g' | sort -u
Junior Dev <junior.dev@yourcompany.tld>
Senior Dev <senior.dev@yourcompany.tld>
root <root@localhost>
OK, you need to get rid of root
and rewrite it to your git account Junior Dev
. The command for this case will look like this:
$ git filter-branch --env-filter '
if [ "$GIT_COMMITTER_EMAIL" = "root@localhost" ]; then
export GIT_COMMITTER_NAME="Junior Dev"
export GIT_COMMITTER_EMAIL="junior.dev@yourcompany.tld"
fi
if [ "$GIT_AUTHOR_EMAIL" = "root@localhost" ]; then
export GIT_AUTHOR_NAME="Junior Dev"
export GIT_AUTHOR_EMAIL="junior.dev@yourcompany.tld"
fi
' --tag-name-filter cat -f -- --all
OK, you have done it, let’s double check by listing the authors again:
$ git log --pretty=full | grep -E '(Author|Commit): (.*)$' | sed 's/Author: //g' | sed 's/Commit: //g' | sort -u
Junior Dev <junior.dev@yourcompany.tld>
Senior Dev <senior.dev@yourcompany.tld>
OK, its gone. Now get it to the remote.
Rewriting the remote author history
Once you have rewritten the local git author history, you will only have to make a forced push of all refs including tags:
$ git push --force --tags origin 'refs/heads/*'
That’s it.
Where does it come short?
Be aware that if any of the commits or tags of an author you want to change are signed
, it will mess up the commit message in the history. It will take the gpg signature of the commit and prepend it to the commit message and will look something like this:
commit 4ac785bf03d4b4f814fa9d139db9b9c7b53df733
Author: cytopia <cytopia@everythingcli.org>
Date: Fri Jul 10 16:03:09 2015 +0200
iQIcBAABCgAGBQJVn9CdAAoJEKrf9Tsovxef+7AP/0rHHruS1o1P28iHPJS7JEuw
FKg1a2MG8DeqwfA93O+chkyl2KfvPEG6yrf369XLAdgR4WkmpCDvK9qYNBxde8NZ
X5S7rGVMKvgdH031o7hYExhMKo1QJrXWzCa7KoEas0/SIAKaqWHojBEpQJO9nBw/
60XMpwxo7MY+Y4a/W603yL3ZgPYgHFHun3pb5sxlFyL4uhdPJXPhPUhAkXdlI4TE
vGt/DwJJ2puDfaQsiOe3Iz6VEYk5s5L22OcYZjBnkgeM14Db9FHAK/KGVgJg0Md0
64HRSyNDCO92CEwCMdv7cqP8cnm2zsk0TvEYpvp7zz1rWkvXK2VAiMfSy8RrUTP8
rE6qDwL7mF27aFAPuVohtddwYMKdcDijffQ/hT7tWeW8zKiI8NcbSENqJ6/SQbqP
mn2WC3vyl2X33WCF3j01BPzq+02B2gMxTr0vnnxewpVDgWKPYGxhxRHXcapo9dva
t8nC6jOXktzHSffWGYFVX/nK1iVoeIrGEPi4n5w3tMX5+HgZUNQCltXRTuUCGCot
LYGMPCRRbSJ8i5KarRHxvxQp5YisQe/pED3NZMg0gEtD2jx9P4Yv7tZwt7CQYnwW
5S336fVLkpJfinrwoaebRgdzd6/rbjsBPd92XPQTYSYG4q5m2EJ6JoaorUCE1H0U
0svoJ7gt7KVVc4urtCiH
=o0wB
-----END PGP SIGNATURE-----
Redirect Errors and Warnings to stderr
The rewriting has created an unsigned multiline commit of the previously signed single-line commit.
Keep that in mind before going to rewrite signed commits.
_