How do I edit git's history to correct an incorrect email address/name

Solution 1:

You can go back and fix all your commits with a single call to git filter-branch. This has the same effect as rebase, but you only need to do one command to fix all your history, instead of fixing each commit individually.

You can fix all the wrong emails with this command:

git filter-branch --env-filter '
    oldname="(old name)"
    oldemail="(old email)"
    newname="(new name)"
    newemail="(new email)"
    [ "$GIT_AUTHOR_EMAIL"="$oldemail" ] && GIT_AUTHOR_EMAIL="$newemail"
    [ "$GIT_COMMITTER_EMAIL"="$oldemail" ] && GIT_COMMITTER_EMAIL="$newemail"
    [ "$GIT_AUTHOR_NAME"="$oldname" ] && GIT_AUTHOR_NAME="$newname"
    [ "$GIT_COMMITTER_NAME"="$oldname" ] && GIT_COMMITTER_NAME="$newname"
    ' HEAD

More information is available from the git docs

Solution 2:

Git's filter-branch command is powerful, but it's horribly unwieldy to use for anything non-trivial, like for example, if you have more than one author to correct.

Here's an alternative I found useful, which uses the .mailmap feature described in the git-shortlog manpage. This provides an author mapping mechanism we can use with git log's formatting facility. We can use it to generate the commands to pick and amend amend a named sequence of commits.

For example, suppose you want to correct the authorship on a branch $BRANCH, starting at a commit $START.

You need to create a .mailmap file in the top directory of your repository which maps the existing author names to he correct ones. You can get a list of the existing author names with:

git shortlog -se

You need to end up with a .mailmap file like this (say):

You <[email protected]>   cowens@localmachine
You <[email protected]>   root@localmachine

Now you can use git log's formatting feature to generate the commands to rewrite $BRANCH as $BRANCH2.

git checkout -b $BRANCH2 $START
git log --reverse --pretty=format:"cherry-pick %H; commit --amend --author='%aN <%aE>' -C %H" $START..$BRANCH | sh - 

The first command creates a new empty branch sprouting from the commit $START. For each commit between $START and then end of $BRANCH, the second command cherry picks the original commit on to the end of the current branch $BRANCH2, and amends it to set the author correctly.

This is also generally applicable - put this in your ~/.gitconfig:

[alias]
    # git reauthor $START..$END
    reauthor = !sh -c 'eval `git log --reverse --topo-order --pretty=format:\"git cherry-pick %H &&  git commit --amend -C %H --author=\\\"%aN <%aE>\\\" && \" $0 ` "echo success" '

So when you need to correct authors, now you just then need to generate a .mapfile and do:

git checkout -b $BRANCH2 $START
git reauthor $START..$BRANCH

The original branch ref can be reassigned to the new one, and the new one deleted:

git checkout $BRANCH
git reset --hard $BRANCH2 # be careful with this command
git branch -d $BRANCH2

Solution 3:

Combining the answer from How do I fix the metainformation on the first commit in git?

### Fix the first commit ###    
# create a temporary tag for the root-most commit so we can reference it
git tag root `git rev-list HEAD | tail -1`
# check it out on its own temporary branch
git checkout -b new-root root
# amend the commit
git commit --amend --author "Foo [email protected]"
# (or if you've set the proper git **config** values)
git commit --amend -C HEAD --reset-author
# now you've changed the commit message, so checkout the original branch again
git checkout @{-1}
# and rebase it onto your new root commit
git rebase --onto new-root root
### Fix the rest of the commits ###
git rebase -i root
# edit the file to read "edit <commit number> for each entry
# amend the commit
git commit --amend --author "Foo [email protected]"
# (or if you've set the proper git **config** values)
git commit --amend -C HEAD --reset-author
# move to the next commit
git rebase --continue    
# continue running the last two commands until you see
# Successfully rebased and updated refs/heads/master.
### Clean up ###
# nuke the temporary branch we created
git branch -d new-root
# nuke the temporary tag we created
git tag -d root

Solution 4:

To follow jedberg's answer: You can use rebase -i and choose to edit the commits in question. If you use git commit --amend --author <AUTHOR DETAILS> and then git rebase continue you can go through and fix the history.

Tags:

Git