Reputation: 48525
I've committed a bunch of commits to a project on Github, however I realized I hadn't set up the proper email and committer full name on the computer I'm currently using to make my commits and therefore the users avatar and email address are not there.
How can I rewrite all past commit email and usernames?
Upvotes: 372
Views: 156221
Reputation: 16705
If you just did this a small number of times on a single branch, it can be fixed with a change of configuration, a new commit, and a rebase.
This is perhaps a less "proper" method than some of the others, but it's easy and uses commands you already know how to use (hopefully?)
Assuming you want to set a new email / name, globally:
git config --global user.name "Your name"
git config --global user.email "[email protected]"
// do something
git add ...
git commit -m 'new commit message'
Change <count>
to required number. It is an integer value. If you don't know what it might be / supposed to be, check git log
. It's somewhat a trial and error thing, sometimes (we won't go into detail as to why)
git rebase -i HEAD~<COUNT>
When in the interactive rebase editor, change pick
to squash
everywhere, but change pick
to drop
for any commits where you merged in another branch (eg master
)... the last part is only relevant if you have done this...
If you don't know how interactive rebase works, this is a good time to learn - it is a very useful tool and you will be amazed when you learn about it (:
git log
git log
should now show a single commit, with the changed email / name
Upvotes: 0
Reputation: 3004
git filter-branch -f --env-filter '
OLD_EMAIL="[email protected]"
CORRECT_NAME="YourCorrectName"
CORRECT_EMAIL="[email protected]"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
After running the above command, you will have forced the overwrite of the backup and updated the author information for all the commits. Now, use the following command to force push the changes to update the remote repository: bash
git push --force --all
Upvotes: 4
Reputation: 49
If you want to rewrite the author on previous commits you will also inadvertently change the commit date to the current day. Ideally, you want to keep the date of the original commits (this is useful if you want to make the history of git contributions accurate - lets say for the Github contributions in your user history overview). You should also be sure to only target commits with a specific author or email, so you don't re-write every single commit.
This is how you do that:
Step 1: Set your email & name to on the local repo
git config user.name "Your name"
git config user.email "[email protected]"
add a --global
flag to set it everywhere.
Step 2: Rebase your commits and change the name & email to the current name & email in your config settings.
git rebase -r <commit-hash> \
--exec 'if [ "$(git log -n 1 --format="%ae")" = “[email protected]” ]; then git commit --amend --no-edit --reset-author --date="$(git log -n 1 --format=%aD)"; fi'
How it works:
By rebasing on a specific commit-hash
you are processing each commit starting from the commit you specified with the hash.
$(git log -n 1 --format="%ae")
retrieves the name of the author from the latest commit (the one being processed) using the git log command with the --format="%ae"
option, which specifies to display only the author email. You can change this part to --format="%an"
to target a author names.
The conditional statement [ "$(git log -n 1 --format="%ae")" = “[email protected]” ]
checks if the name of the author from the latest commit matches the specific email “[email protected]”.
If the condition is true, the subsequent git commit --amend --no-edit --reset-author --date="$(git log -n 1 --format=%aD)"
command will be executed as part of the --exec option during the rebase operation. Its important to add the --date=
flag with the matcher so that we don't change the original commit date during the rebase. This is selecting the most recent commit of the branch (which is the one you are currently processing) and using that commit's date thereby leaving the commit message with the same date.
But be careful, you are changing git history and you are changing the commit hashes for each node on the branch. You will have to force push the change up to a public repository (if you are changing a branch that has already been pushed up).
Using this command goes without saying - only change commit emails & author names if there has been some error in the email that was used for the commit, and you want to attribute the proper developer. You may have committed for someone else, or you may have forgot to set the proper name & email before starting your repo.
Upvotes: 4
Reputation: 4692
First update the username and email
Update them global or in your current repository
git config --global user.name "Name"
git config --global user.email "<[email protected]>"
Note that you can update them in .git/config file, just append this section with your info
[user]
name = new name
email = new email
Then run this command to update all previous commits
git rebase -r --root --exec "git commit --amend --no-edit --reset-author"
Upvotes: 30
Reputation: 713
After applying Olivier Verdier's answer:
git filter-branch -f --env-filter \
"GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; \
GIT_COMMITTER_NAME='committed-name'; GIT_COMMITTER_EMAIL='committed-email';" HEAD
...to push the changed history on the original repository use:
git push origin +yourbranch
The above command (note the plus) forces rewriting the history on the original repo as well. Use with caution!
Again, WARNING: this will make ALL commits as committed by Newname/newemail! The scenario is where you have a repo with only one author who committed using different identities by mistake and you want to fix it.
Upvotes: 49
Reputation: 3087
An alternative to rewriting the history, if you mainly care about the local repo display names, is the .mailmap file
, which is basically a list of names and emails. For example, placing this in a .mailmap
file in the root of a repo:
Tamika Page <[email protected]>
Orlando Cervantes <[email protected]> Orlando Jackson <[email protected]>
Jared Michael <[email protected]> <jared@desktop.(none)>
will result in any commits attributed to [email protected]
being shown with the name Tamika Page, regardless of the Committer Name, commits attributed to Orlando Jackson <[email protected]>
being displayed as Orlando Cervantes, and the pesky <jared@desktop.(none)>
commits being attributed to [email protected]
. For full details, check out the git documentation for this feature - since it is built into git it should work for any reasonably new git client.
There's a big caveat here though: while it's been supported for quite a while in the official git client, support in various git implementations, notably the big web interfaces, isn't guaranteed - see this question, where consensus on whether GitHub respects it is mixed but seems negative. I threw together quick test repos on GitHub and GitLab and neither seem to pay attention to .mailmap
, unfortunately.
As mentioned in @paradocslover's answer, the services have their own interfaces to do similar things, but you have to set that up per-service, and it won't affect your local copy at all. Because .mailmap
is part of the repo, it will work locally for anyone who clones your repo (you can clone the repos linked above to see for yourself), but it seems it won't show in the web interfaces I tested.
For some cases you do want to rewrite the history, of course, but that can be rather invasive and comes with all the standard caveats, so for some situations it's nice to have this option, which may be sufficient, especially if rewriting isn't practical.
Upvotes: 5
Reputation: 3294
The answers already present are complete. But are you sure, you need those? For eg. I was facing a similar issue but the answers here were overkill for that case. My case and the solution are described below:
Assume you have two email ids, [email protected]
and [email protected]
. It is possible that the previous commits were through [email protected]
which is not the email id that you want. In that case, one option is to simply link [email protected]
to your GitHub account.
Find the option to add the email in the Emails section on the settings page.
The first three steps mentioned on the github page will be enough.
[email protected]
should be set as primary email id.Upvotes: 6
Reputation: 509
https://help.github.jp/enterprise/2.11/user/articles/changing-author-info/
#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="[email protected]"
CORRECT_NAME="yourName"
CORRECT_EMAIL="yourEmail"
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]
then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
this totally worked for me. After git push, make sure to see update on git's web portal. If the commit was still not linked to my account, shown default thumbnail image next to the commit and it was not reflected on my contributions timeline chart, go to the commit url and append .patch at the end of the url, and verify the name and email are correct.
Upvotes: 33
Reputation: 6315
You can add this alias:
git config --global alias.change-commits '!'"f() { VAR=\$1; OLD=\$2; NEW=\$3; shift 3; git filter-branch --env-filter \"if [[ \\\"\$\`echo \$VAR\`\\\" = '\$OLD' ]]; then export \$VAR='\$NEW'; fi\" \$@; }; f"
To change the author name:
git change-commits GIT_AUTHOR_NAME "old name" "new name"
or the email for only the last 10 commits:
git change-commits GIT_AUTHOR_EMAIL "[email protected]" "[email protected]" HEAD~10..HEAD
Alias:
change-commits="!f() { VAR=$1; OLD=$2; NEW=$3; shift 3; git filter-branch --env-filter \"if [[ \\\"$`echo $VAR`\\\" = '$OLD' ]]; then export $VAR='$NEW'; fi\" \$@; }; f"
Source: https://github.com/brauliobo/gitconfig/blob/master/configs/.gitconfig
Upvotes: 422
Reputation: 49146
See here:
git filter-branch -f --env-filter \
"GIT_AUTHOR_NAME='Newname'; GIT_AUTHOR_EMAIL='newemail'; \
GIT_COMMITTER_NAME='committed-name'; GIT_COMMITTER_EMAIL='committed-email';" HEAD
Upvotes: 175
Reputation: 1446
Considering use of git-filter-branch
is not desired, to do the same thing in git-filter-repo (you may need to install it first with pip install git-filter-repo
):
git-filter-repo --name-callback 'return name.replace(b"OldName", b"NewName")' --email-callback 'return email.replace(b"[email protected]", b"[email protected]")'
If repository is original, w/o remote, you will have to add --force
to force rewrite. (You may want to create backup of your repo before doing this.)
If you do not want to preserve refs (they will be displayed in branch history of Git GUI), you will have to add --replace-refs delete-no-add
.
For more advanced features, see "Filtering of names & emails".
P.S. Stolen and improved from https://stackoverflow.com/a/59591928/714907.
Upvotes: 67
Reputation: 1768
For those that just want the easy copy paste version (aside from updating emails and names):
git config alias.change-commits '!'"f() { VAR=\$1; OLD=\$2; NEW=\$3; shift 3; git filter-branch --env-filter \"if [[ \\\"\$\`echo \$VAR\`\\\" = '\$OLD' ]]; then export \$VAR='\$NEW'; fi\" \$@; }; f "
git change-commits GIT_AUTHOR_NAME "<Old Name>" "<New Name>" -f
git change-commits GIT_AUTHOR_EMAIL <[email protected]> <[email protected]> -f
git change-commits GIT_COMMITTER_NAME "<Old Name>" "<New Name>" -f
git change-commits GIT_COMMITTER_EMAIL <[email protected]> <[email protected]> -f
Upvotes: 14
Reputation: 28100
If you have already pushed some of your commits to the public repository, you do not want to do this, or it would make an alternate version of the master's history that others may have used. "Don't cross the streams... It would be bad..."
That said, if it is only the commits you have made to your local repository, then by all means fix this before you push up to the server. You can use the git filter-branch
command with the --commit-filter
option, so it only edits commits which match your incorrect info, like this:
git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "wrong_email@wrong_host.local" ];
then
GIT_AUTHOR_NAME="Your Name Here (In Lights)";
GIT_AUTHOR_EMAIL="correct_email@correct_host.com";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
Upvotes: 102