How to amend several commits in Git to change author
Solution 1
Warning: now deprecated in favor of filter-repo.
Rebase/amend seems inefficient, when you have the power of filter-branch at your fingertips:
git filter-branch --env-filter 'if [ "$GIT_AUTHOR_EMAIL" = "incorrect@email" ]; then
GIT_AUTHOR_EMAIL=correct@email;
GIT_AUTHOR_NAME="Correct Name";
GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL;
GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; fi' -- --all
(split across lines for clarity, but not necessary)
Be sure to inspect the result when you're done, to make sure that you didn't change anything you didn't mean to!
Solution 2
The interactive rebase approach is pretty nice when used in conjunction with exec. You can run any shell command against a specific commit or all commits in the rebase.
First set your git author settings
git config --global user.name "John Doe"
git config --global user.email [email protected]
Then to reset the author for all commits after the given SHA
git rebase -i YOUR_SHA -x "git commit --amend --reset-author -CHEAD"
This will pop up your editor to confirm the changes. All you need to do here is save and quit and it will go through each commit and run the command specified in the -x flag.
Per @Dave's comment below, you can also change the author while maintaining the original timestamps with:
git rebase -i YOUR_SHA -x "git commit --amend --author 'New Name <[email protected]>' -CHEAD"
Solution 3
To change the author only for the last commit:
git commit --amend --author 'Author Name <[email protected]>' --no-edit
Suppose you only want to change the author for the last N commits:
git rebase -i HEAD~4 -x "git commit --amend --author 'Author Name <[email protected]>' --no-edit"
NOTES
- the
--no-edit
flag makes sure thegit commit --amend
doesn't ask an extra confirmation - when you use
git rebase -i
, you can manually select the commits where to change the author,
the file you edit will look like this:
pick 897fe9e simplify code a little
pick abb60f9 add new feature
exec git commit --amend --author 'Author Name <[email protected]>' --no-edit
pick dc18f70 bugfix
Solution 4
The highest voted answer here is now out of date. Git shows this scary warning when using git filter-branch -
WARNING: git-filter-branch has a glut of gotchas generating mangled history
rewrites. Hit Ctrl-C before proceeding to abort, then use an
alternative filtering tool such as 'git filter-repo'
(https://github.com/newren/git-filter-repo/) instead.
To use the filter-repo -
-
Install the command, using pip -
pip install git-filter-repo
(Needs git v2.22+ and python v3.5+. Check withgit --version && python3 --version
) -
Fix the commits
-
Email only
git filter-repo --email-callback ' return email if email != b"incorrect@email" else b"correct@email" '
-
Email and author name
git filter-repo --commit-callback ' if commit.author_email == b"incorrect@email": commit.author_email = b"correct@email" commit.author_name = b"Correct Name" commit.committer_email = b"correct@email" commit.committer_name = b"Correct Name" '
-
Make sure the indents are there when you paste the command in your terminal. The callback uses python syntax so indents are important.
Read more about filter-repo callbacks here.
Solution 5
This method was documented by GitHub for this very purpose (though GitHub has since removed it). The steps are:
- Open the terminal and make a bare clone of your repo
git clone --bare https://github.com/user/repo.git
cd repo
- Edit the following script (replacing
OLD_EMAIL
,CORRECT_EMAIL
, andCORRECT_NAME
)
#!/bin/sh
git filter-branch --env-filter '
OLD_EMAIL="[email protected]"
CORRECT_NAME="Your Correct Name"
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
- Copy/paste the script into your terminal and press enter to run it.
- Push your changes with
git push --force --tags origin 'refs/heads/*'
and you're done!
Related videos on Youtube
Sam Liao
Updated on March 29, 2022Comments
-
Sam Liao about 2 years
I have made a series of commits in Git and I realise now that I forgot to set my user name and user email properties correctly (new machine). I have not yet pushed these commits to my repository, so how can I correct these commits before I do so (only the 3 latest commits on the master branch)?
I have been looking at
git reset
andgit commit -C <id> --reset-author
, but I don't think I'm on the right track.-
craq over 5 yearsAnother reason you might want to change the email property is this github error:
remote: error: GH007: Your push would publish a private email address.
... ` ! [remote rejected] master -> master (push declined due to email privacy restrictions)`. -
scai almost 4 yearsAlso see stackoverflow.com/q/750172/1340631.
-
-
max pleaner over 9 yearsmind explaining this a bit more? not sure what filter branch is
-
Brad Hein about 9 yearsThank you for introducing me to the -x option. Its pretty awesome! for the -i option I used HEAD~4 to fix my email address on my last 4 commits. worked like a charm.
-
alediaferia almost 9 years@maxpleaner
git filter-branch --help
is pretty straightforward :) -
luator over 8 yearsThis is much simpler than
filter-branch
if you just want to fix your last commits :). Note however, that this changes the timestamp of the commits. -
Piotr Zierhoffer over 8 yearsAs
filter-branch
is not that straight-forward, I also give my love to this one. Almost everything you usually do messing up your history is related torebase -i
, and this option fits this scheme perfectly. -
Dave almost 8 yearsTo change the author but maintain the original timestamps, use
git rebase -i YOUR_SHA -x "git commit --amend --author 'New Name <[email protected]>' -CHEAD"
-
Tobias Kienzler about 7 yearssee also help.github.com/articles/changing-author-info, which also adds
--tag-name-filter cat
to thefilter-branch
in order to migrate tags to the new history. It also uses--branches --tags
instead of--all
, which only rewrites branch and tag history and leaves otherrefs
alone (though that probably doesn't make much of a difference unless e.g. you're usinggit-notes
) -
Jeff Paquette almost 7 yearsNote that it's important to use single quotes and not backticks around the command!
-
Ashish Negi over 6 yearsfor all commits from root. git rebase -i --root UPTO_COMMIT_SHA -x "git commit --amend --author 'NEW_CHANGE' --no-edit"
-
nmz787 about 6 yearsto perform this on just the last two commits, I replaced
-- --all
withHEAD~1..HEAD
-
Connor almost 6 yearsThis did not work for me. tried both the short and the long sha for the commit I wanted changed and it remained unchanged when I ran
git log
-
Bruno 82 almost 6 yearsJust tried the second version (the one that keeps the original timestamps) and worked like a charm. Thank you so much! This should definitely be the accepted answer
-
Dan M. over 5 years@Connor
git log
also showed old authorship for me, but git status correctly identified new commits and after force push they were as I intended. -
ahadcse over 5 yearsIt works in local branch but when I am trying to push in origin I cannot. When I am trying to push, git is telling me to pull. When I am pulling I am getting the following error: "fatal: refusing to merge unrelated histories"
-
Jona about 5 years@nmz787 last two commits is
HEAD~2..HEAD
-
nmz787 about 5 years@Jona I'm pretty sure that would yield the last 3 commits... HEAD, HEAD-1, and HEAD-2... that's 3 total
-
Jona about 5 years@nmz787 How many logs are shown if you do
git log HEAD~2..HEAD
? -
gfullam about 5 yearsTo rebase all commits including the root use:
git rebase -i --root …
instead of passing a SHA. -
enigment almost 5 yearsI followed the same instructions on GitHub that you referenced, and GitHub looks right now. However, I'm a Git newb and not sure how to sync my local repo back up after that. When I pull I get the same "refusing to merge unrelated histories" error mentioned in another answer. I think I need to rebase against that new commit history, but I'd very much appreciate more specific steps.
-
stevec almost 5 years@enigment if you are happy with the repo as it is on github, you can delete (or perhaps move to another location) the folder you have locally and simply clone from github
-
enigment almost 5 yearsThanks, I know, but that doesn't seem like the idiomatic GitHub/Git way.
-
AdamHurwitz about 4 yearsRemember to use
git push -f
afterwards to push the changes to the origin. -
donquixote about 4 yearsI recommend to add
--rebase-merges
(short-r
) option, to keep the topology of your branch intact if it contains some merges. -
smmehrab over 3 yearsThank you so much!
git rebase -i YOUR_SHA -x "git commit --amend --author 'New Name <[email protected]>' -CHEAD"
Worked like a charm! -
msleigh over 3 yearsThe
git filter-branch
command now comes with a warning, andfilter-repo
(which is third-party) is recommended instead: github.com/newren/git-filter-repo. The alternative command would be along the lines ofecho '<correct@email> <incorrect@email>' > .mailmap ; git filter-repo --use-mailmap
. -
David Burson over 3 yearsI was confused by "all you need to do is save and quit" since there was no "Save" option. For me, just ctrl-X to exit was all I had to do, and it executed correctly.
-
a_hardin about 3 yearsIf you're a Windows user and the command opens the changes in vim, press Esc Z Z to save and quit. (Note the capital Zs)
-
H Aßdøµ about 3 yearsAnd don't forget to force the push
git push --force
-
Camilo about 3 yearsJust tried @Dave answer but the original timestamps are not maintained (you can check it here github.com/oncet/coel/commits/temp). Using git 2.25.1.
-
jv-k over 2 yearsFrom the docs: 'WARNING! The rewritten history will have different object names for all the objects and will not converge with the original branch. You will not be able to easily push and distribute the rewritten branch on top of the original branch. Please do not use this command if you do not know the full implications, and avoid using it anyway, if a simple single commit would suffice to fix your problem. (See the "RECOVERING FROM UPSTREAM REBASE" section in git-rebase[1] for further information about rewriting published history.)'. Careful using
--all
! -
charsi over 2 yearsAdded an answer that uses filter-repo as recommended by git.
-
René K over 2 years@Camilo Same for me (git version 2.28.0.windows.1)
-
TeNNoX about 2 yearsSubmitted an edit to warn about this: stackoverflow.com/suggested-edits/5320642
-
Nelu about 2 yearsThank you. It worked! If you're getting
zsh: command not found: pip
on a Mac, try pip3 -pip3 install git-filter-repo
. -
sshine about 2 years@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 thefilter-branch
(orfilter-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 agit commit --amend --author="John Doe ..."
here, and you can see that the committer is not John Doe. -
nmz787 about 2 yearson Windows (in
ConEmu
terminal), in avenv
, I had to swap quotes and make it a one-liner, and add--force
(because I made commits since last pushing):git filter-repo --force --email-callback " return email if email != b'wrong@email' else b'correct@email'"
-
Steven about 2 yearsTo amend while keeping the date:
git rebase -i YOUR_SHA -x 'git commit --amend --reset-author --no-edit --date="$(git log -n 1 --format=%aD)"'
-
matttm almost 2 yearsAs a note, you can use
--root
in place ofHEAD
if trying to specify every commit of the rreo.