43

So I read a lot about how to change previous commit's email address but for some reason mine is not updating.

I did like 40 commits to my private repo with my local email (nameofMyComputer@kevin.local) which is bad since this email is not associated(and it can't be) with Github.

I then remembered that I needed to set the git.config before and so I did:

 git config user.email "newemail@example.com"

and did a test commit and it worked perfectly.

Is there a way I can revert all my previous commits to this new email?

I read this question on SO How do I change the author and committer name/email for multiple commits? and used this

 git filter-branch -f --env-filter "                         
                    GIT_AUTHOR_EMAIL='newemail@example.com'; 
                    GIT_COMMITTER_EMAIL='newemail@example.com';
                    " 
                HEAD

But it DID NOT work... I can still see the email of my previous commits with the .patch extension as the .local email address

Syscall
  • 19,327
  • 10
  • 37
  • 52
Kevin Cohen
  • 1,211
  • 2
  • 15
  • 22
  • I believe you are going to have to rewrite the history of your branch to change the emails, which seem to appear along with the name of the committer. If you can accept this, then `filter-branch` or `git rebase` should do the trick. – Tim Biegeleisen Jan 18 '16 at 09:16
  • 2
    Possible duplicate of [How to amend several commits in Git to change author](http://stackoverflow.com/questions/4981126/how-to-amend-several-commits-in-git-to-change-author) – Chris Maes Jan 18 '16 at 20:13

3 Answers3

77

You can indeed do his for many commits at once like this:

git rebase -i HEAD~40 -x "git commit --amend --author 'Author Name <author.name@mail.com>' --no-edit"

I worked this out better in this answer.

Community
  • 1
  • 1
Chris Maes
  • 35,025
  • 12
  • 111
  • 136
  • 2
    and then `git push --force`? – Jonah Mar 24 '20 at 17:34
  • 3
    since this rewrites your commits, yes. Consider using `git push --force-with-lease` to make sure not to crush work from your collegues. – Chris Maes Mar 24 '20 at 17:40
  • Thanks Chris Maes! :) For anyone else using this, please make sure to change HEAD~40 to however many commits you want to affect. Read more at https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History – Oscar Andersson Aug 30 '21 at 07:08
  • works for me! thanks! – keypoint Dec 16 '21 at 23:11
  • 3
    @ChrisMaes: Please note that **`git commit --amend --author ...` does not change the committer, only the author!** So while it may *appear* that your email was changed, there is, in fact, metadata in the repository that says who the old committer is. While the `filter-branch` (or `filter-repo`) methods are more crude, they actually change both. Proof: `curl -s https://api.github.com/repos/sshine/author-committer/commits | jq '.[0].commit | { author, committer }'` -- I did a `git commit --amend --author="John Doe ..."` here, and you can see that the committer is not John Doe. – sshine Feb 03 '22 at 00:42
15

As you mentioned in your question (the link to the answer you found), this is the script indeed.

Note:

filter-branch is doing a rebase (will rewrite the history of the branch) which means that everyone who had a copy of the branch will have to delete and checkout it again.


The script origin is from here - Git-Tools-Rewriting-History:

# Loop over all the commits and use the --commit-filter
# to change only the email addresses

git filter-branch --commit-filter '

    # check to see if the committer (email is the desired one)
    if [ "$GIT_COMMITTER_EMAIL" = "<Old Email>" ];
    then
            # Set the new desired name
            GIT_COMMITTER_NAME="<New Name>";
            GIT_AUTHOR_NAME="<New Name>";

            # Set the new desired email
            GIT_COMMITTER_EMAIL="<New Email>";
            GIT_AUTHOR_EMAIL="<New Email>";

            # (re) commit with the updated information
            git commit-tree "$@";
    else
            # No need to update so commit as is
            git commit-tree "$@";
    fi' 
HEAD

What does the script do?

Its looping over all your commits and once you find match its replacing the name and email of the committer.

Community
  • 1
  • 1
CodeWizard
  • 128,036
  • 21
  • 144
  • 167
  • I did this, but when I view my past commits, it is still showing as my local email address... any ideas why? – Kevin Cohen Jan 18 '16 at 20:41
  • Where do you see your email? on the same branch or is it on a different branch? – CodeWizard Jan 18 '16 at 21:41
  • Same branch.. For some reason I did it then I pushed and what it happened is that it duplicated all of my commits again with the new email, BUT, still doesn't show in the contributions calendar which is the whole point of this question – Kevin Cohen Jan 19 '16 at 16:28
  • I didn't understood what happened. can you provide screen shoot? – CodeWizard Jan 21 '16 at 12:12
3

Here's a version based on Chris Maes' answer that only applies the change to commits with a matching email address, and uses rebase --root (since git 1.7) to write from the beginning of your history.

If you want to choose the a specific base commit, you'll want to remove --root, and use the refspec you want.

function reauthor_all {
  if [[ "$#" -eq 0 ]]; then
    echo "Incorrect usage, no email given, usage is: $FUNCNAME <email>" 1>&2
    return 1
  fi

  local old_email="$1"

  # Based on
  # SO: https://stackoverflow.com/a/34863275/9238801

  local new_email="$(git config --get user.email)"
  local new_name="$(git config --get user.name)"

  # get each commit's email address ( https://stackoverflow.com/a/58635589/9238801 )
  # I've broken this up into two statements and concatenated
  # because I want to delay evaluation

  local command='[[ "$(git log -1 --pretty=format:'%ae')" =='
  command+=" '$old_email' ]] && git commit --amend --author '$new_name <$new_email>' --no-edit || true"


  git rebase -i --root -x "$command"
}

Use on my own repo:

reauthor_all "personal.email@gmail.com"
hint: Waiting for your editor to close the file... 
Press ENTER or type command to continue
Executing: [[ "$(git log -1 --pretty=format:%ae)" == 'personal.email@gmail.com' ]] && git commit --amend --author 'Matthew Strasiotto <39424834+matthewstrasiotto@users.noreply.github.com>' --no-edit || true
Executing: [[ "$(git log -1 --pretty=format:%ae)" == 'personal.email@gmail.com' ]] && git commit --amend --author 'Matthew Strasiotto <39424834+matthewstrasiotto@users.noreply.github.com>' --no-edit || true
[detached HEAD 1e281b5] First Message
...etc

You'll need to force push when it looks right eventually, and this WILL change commit shas, so that's going to cause a whole host of other problems.

  • A note: I use string concatenation to delay the evaluation of certain parts of the command, as can been seen in the output. This feels like an ugly hack, but appears to be the most portable ugly hack- Newer version of bash (>= 4.4)seem to support `${param@Q}` for delaying evaluation, but if you're on OSX, you'll start with 3.2, & I've found solutions that abstract manual `\\` escaping into bash functions, but `rebase -x 'function_in_bashrc'` wont find `function_in_bashrc`. I mean, maybe there's no such thing as a bash script that doesn't include an ugly hack – Matthew Strasiotto Feb 19 '21 at 04:00
  • If anyone has better ideas for delaying evaluation of parameter substitution/shell expansion, please weigh in – Matthew Strasiotto Feb 19 '21 at 04:01