The short answer
Set the right email for the repo first, with git config user.email sam@acme.dev. Then fix the last commit with git commit --amend --no-edit --reset-author. For several commits, run git rebase -r <base> --exec 'git commit --amend --no-edit --reset-author', where <base> is the last commit that was right. Both rewrite history: fine before you push, but after a push you need git push --force-with-lease, and anyone who pulled the old commits has to reset to the new ones.
On this page
Check which email a commit used
Every commit records an author, who wrote it, and a committer, who last applied it. Usually they're the same. Show both for the last commit:
git log -1 --format='author: %an <%ae>%ncommitter: %cn <%ce>'Then find where the wrong email came from, so the fix sticks:
git config --show-origin --get user.emailIf it prints ~/.gitconfig, this repo has no email of its own and uses your global one. Set the right one for the repo with git config user.email sam@acme.dev, or for a whole folder with an includeIf rule (below).
Fix the last commit
git commit --amend --no-edit --reset-author--reset-author takes the name and email from your config, so set them first. --no-edit keeps the message. If you'd rather name the author without changing config, use --author:
git commit --amend --no-edit --author="Sam Lee <sam@acme.dev>"| --reset-author | --author="Name <email>" | |
|---|---|---|
| Author name and email | From your current config | Exactly what you type |
| Author date | Reset to now | Kept |
| Committer | From your current config | Also from your current config, so it stays wrong until you fix the config |
Author name and email
- --reset-author
- From your current config
- --author="Name <email>"
- Exactly what you type
Author date
- --reset-author
- Reset to now
- --author="Name <email>"
- Kept
Committer
- --reset-author
- From your current config
- --author="Name <email>"
- Also from your current config, so it stays wrong until you fix the config
Fix several commits
Rebase replays each commit after <base> and runs the amend after each one. Use the last good commit, or the branch you started from, as the base:
git rebase -r origin/main --exec 'git commit --amend --no-edit --reset-author'git rebase -r --root --exec 'git commit --amend --no-edit --reset-author'-r keeps merge commits as merges instead of flattening them. To change only the commits with the wrong email, list them first with git log --author=samdev@example.com --format='%h %ae %s'. To keep each commit's original date, use --author="Sam Lee <sam@acme.dev>" in the --exec command instead of --reset-author.
If you've already pushed
If the wrong email is yours, there's a fix that rewrites nothing: add the address to the right GitHub account under Settings → Emails and verify it. GitHub links commits to accounts by email, so the existing commits show up under that account.
If you do rewrite a pushed branch, collaborators update with git fetch and then git reset --hard origin/<branch>, which throws away any local commits they hadn't pushed, so they should rebase those onto the new branch first.
Stop it happening again
- Set the email per folder with
includeIf "gitdir:~/work/"in~/.gitconfig, so new repos in that folder commit as work without anyone remembering. - Make Git refuse to guess.
git config --global user.useConfigOnly truestops Git from inventing an email from your Mac's name. Combine it with no global email and Git refuses to commit until the repo or folder sets one. - Check before you push with a pre-push hook that compares each new commit's author with the repo's email.
#!/bin/sh
# Refuse to push commits whose author email differs from this repo's user.email.
expected=$(git config user.email)
zero=$(git hash-object --stdin </dev/null | tr '0-9a-f' '0')
while read -r local_ref local_sha remote_ref remote_sha; do
[ "$local_sha" = "$zero" ] && continue
if [ "$remote_sha" = "$zero" ]; then range="$local_sha --not --remotes"; else range="$remote_sha..$local_sha"; fi
bad=$(git log --format=%ae $range | grep -v -x -F "$expected" | head -n 1)
if [ -n "$bad" ]; then
echo "pre-push: a commit is authored by $bad, but this repo uses $expected" >&2
exit 1
fi
done
exit 0A repo has one pre-push hook. If you use husky, lefthook or the pre-commit framework, or git config core.hooksPath prints a folder, add the check to that tool's hook instead of replacing it.
The faster way: Wrong identity alerts in iKnowMyMac
iKnowMyMac checks each new commit's author against the profile for that repo, within seconds of the commit. If it's wrong, an alert names the repo and the email, and says whether the commit has been pushed.