How to update git commit author, but keep original date when amending?
Asked Answered
S

8

43

If the commits are already made and pushed to the repository, and if want to change an author for some particular commit I can do it like this:

git commit --amend --reset-author

But, that will change the original committed date.

How can I reset author, but keep the original committer date?

Shari answered 23/12, 2016 at 12:33 Comment(1)
Terminology nitpick: The documented date formats are called author-date and committer-date. Answers reasonably assumes originally committed date to mean author-date. Would update the question to clarify, but the review queue is full.Seeker
S
10

Hm, at the end, I have found a bit easier solution for me. I have created a script in directory containing the git project gitrewrite.sh, and modified its permissions so it could be exectured:

$ chmod 700 gitrewrite.sh

Then I placed in the shell script:

#!/bin/sh

git filter-branch --env-filter '
NEW_NAME="MyName"
NEW_EMAIL="[email protected]"
if [ "$GIT_COMMIT" = "afdkjh1231jkh123hk1j23" ] || [ "$GIT_COMMIT" = "43hkjwldfpkmsdposdfpsdifn" ]
then
    export GIT_COMMITTER_NAME="$NEW_NAME"
    export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
    export GIT_AUTHOR_NAME="$NEW_NAME"
    export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

And then run the script in terminal:

$ ./gitrewrite.sh

And that's it. The history has been rewritten.

Push the code to the repository and add a force flag.

$ git push -f

Important note:

For the others reading it, keep in mind that this is going to create new references in the git history so do this only in private repository or the one which is still not shared with others as it could cause broken references!

Mine was a private repo, so no worries there for that part. If it is public, then perhaps using the other suggested answer could be a better option.

Shari answered 23/12, 2016 at 14:39 Comment(2)
Wow! That's a complex workaround to avoid seven backspaces and typing ones name and email...Seeker
@Seeker I would even say - an impossible workaround for the thing that nobody asked for - to type seven backspaces. If it would be six backspaces, then ok, but 7. Omg. No.Shari
E
56

Here's how to do it with rebase and keep both the commit date and the author date:

git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="%cD" GIT_AUTHOR_DATE="%aD" git commit --amend --no-edit --reset-author' rebase -f <commit/branch before wrong author and email, or --root to rebase all>

Based off this Reddit thread.

Ecumenism answered 11/8, 2022 at 1:23 Comment(3)
Best! Answer! Ever!Mcallister
Btw, you could remove the -i flag so you won't be shown the editor. I.e: git -c rebase.instructionFormat='%s%nexec GIT_COMMITTER_DATE="%cD" GIT_AUTHOR_DATE="%aD" git commit --amend --no-edit --reset-author' rebase <commit before wrong author and email>. Also, if changing all of the commits starting from the first one is desired, then instead of providing a commit, just pass a --root flag.Murmansk
If I omit -i I get a message like Current branch foo is up to date., but adding -f makes it work. --root works as expected! Thanks, I'll update my answer!Ecumenism
T
34

As mentioned in some other answers you would probably use:

git commit --amend --reset-author --no-edit --date="<old-date>"

While this works it's a lot of manual copying or typing to get the old date in place. You might want to get the date automatically, by getting only the date of the last entry in the log:

git log -n 1 --format=%aD

Combine the two and use some shell magic:

git commit --amend --reset-author --no-edit --date="$(git log -n 1 --format=%aD)"

This automatically sets the date of the last commit in the log, aka the one to be amended, as date of the new commit with the changed author.

Now changing the author on a larger amount of commits, say because you forgot to set the author in the cloned git repo, an interactive rebase is your friend:

git rebase -i <commit before wrong author and email>

You then change all commits you want to adjust from pick to edit and save the file. Git stops on every commit to be edited and you rerun:

git commit --amend --reset-author --no-edit --date="$(git log -n 1 --format=%aD)" && \
    git rebase --continue

If it's a reasonable small number of commit you can repeat this command using the shells arrow-up key until until the rebase finishes. If there is a larger number of commits, that typing arrow-up + return becomes too tedious you might want to create a small shell script that repeats the above command until the rebase finishes.

Tradesman answered 14/4, 2020 at 21:36 Comment(6)
No need to repeat that command. You can use -x <cmd> to append exec <cmd> after each line of the todo list. Of course, you should remove exec <cmd> after commits that you don't want to edit.Pronominal
@Pronominal So the entire thing would be git rebase -i <commit> -x 'git commit --amend --reset-author --no-edit --date="..." && git rebase --continue'?Accuracy
This is super helpful! Quick note though: --date only seems to update the author date. To update the committer date (what's shown in github) as well, I had to tweak the script to store the GIT_COMMITTER_DATE on each amend: export GIT_COMMITTER_DATE=$(git log -n 1 --format=%aD) && git commit --amend --reset-author --no-edit --date="$GIT_COMMITTER_DATE" && git rebase --continueUnilocular
I didn't spend much time looking into this, so I'm sure someone here could optimize it even more. But in case it's helpful for anyone else, I added this as a git alias to my .gitconfig: update-user-keep-date = "!export GIT_COMMITTER_DATE=$(git log -n 1 --format=%aD);git commit --amend --reset-author --no-edit --date=\"$GIT_COMMITTER_DATE\";git rebase --continue" So now just running git update-user-keep-date on every commit amend easily updates the commit.Unilocular
Yes, this doesn't update commit dateBlackmon
@Unilocular thank you! This is what I used, to preserve the original date for the commit: export GIT_COMMITTER_DATE=$(git show --no-patch --format=%aD) && git commit --amend --reset-author --no-edit --date="$GIT_COMMITTER_DATE" && git rebase --continueWaters
S
10

Hm, at the end, I have found a bit easier solution for me. I have created a script in directory containing the git project gitrewrite.sh, and modified its permissions so it could be exectured:

$ chmod 700 gitrewrite.sh

Then I placed in the shell script:

#!/bin/sh

git filter-branch --env-filter '
NEW_NAME="MyName"
NEW_EMAIL="[email protected]"
if [ "$GIT_COMMIT" = "afdkjh1231jkh123hk1j23" ] || [ "$GIT_COMMIT" = "43hkjwldfpkmsdposdfpsdifn" ]
then
    export GIT_COMMITTER_NAME="$NEW_NAME"
    export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
    export GIT_AUTHOR_NAME="$NEW_NAME"
    export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

And then run the script in terminal:

$ ./gitrewrite.sh

And that's it. The history has been rewritten.

Push the code to the repository and add a force flag.

$ git push -f

Important note:

For the others reading it, keep in mind that this is going to create new references in the git history so do this only in private repository or the one which is still not shared with others as it could cause broken references!

Mine was a private repo, so no worries there for that part. If it is public, then perhaps using the other suggested answer could be a better option.

Shari answered 23/12, 2016 at 14:39 Comment(2)
Wow! That's a complex workaround to avoid seven backspaces and typing ones name and email...Seeker
@Seeker I would even say - an impossible workaround for the thing that nobody asked for - to type seven backspaces. If it would be six backspaces, then ok, but 7. Omg. No.Shari
D
9
  1. If you are doing rebase then use committer-date-is-author-date to keep the date same as before.

    $ git commit --amend --committer-date-is-author-date
    
  2. For normal amend, copy the original committer time and override the time when amending using --date flag.

    $ git log                     # copy the 'original-committer-time'
    $ git commit --amend --reset-author --date="<original-committer-time>"
    
    # e.g. git commit --amend --date="Fri Dec 23 18:53:11 2016 +0600"
    
Decussate answered 23/12, 2016 at 12:40 Comment(10)
:) Is there some more global approach, rather then manually editing datetime?Shari
Try committer-date-is-author-date flag.Decussate
Ok, but btw the --committer-date-is-author-date is used when doing a rebase, not when committing. When using with git commit --committer-date-is-author-date it reports as unknown command. In both cases it doesn't work.Shari
Yes. --committer-date-is-author-date is used when rebasing. I think there is no direct flag for not changing date while doing normal amend . So, you can use --date flag for overriding date with original-committer-date.Decussate
Yes, at the very end that could be one of the solutions. Will check it out, and return to the question to mark it.Shari
An option might be to commit --fixup HEAD and rebase interactively onto HEAD~2 with --autosquash and --committer-date-is-author-dateParodist
Not seeing any 'original-committer-time' after running git log.Heavenly
@Heavenly original-committer-time is actually the "Date" you want to set for that commit!Decussate
The committer date is not necessarily author date at this point.Bruton
git commit says unknown option `committer-date-is-author-date'Bookstall
P
8

We can get the required behaviour using rebase autosquash:

git commit --fixup HEAD
git rebase --autosquash --committer-date-is-author-date HEAD~2

The first command creates a new commit as a fixup commit on the current HEAD commit. A fixup commit means if rebase is run later with --autosquash, this new commit will be fixed up on the old one (same as fixup in interactive rebase). The second one triggers a rebase onto HEAD~2 - means 2nd level parent of HEAD, or the parent of the original HEAD (before we added the fixup) so this will trigger a rebase with the 2 commits only. Since we added --autosquash, the commits will be squashed together and adding -- committer-date-is-author-date means it will use the date of the original authored commit rather than this current date in which the new commit is really created.

Warning: If the commits are already pushed and if you rewrite the pushed commits in any way and force push, you will be rewriting published history, which is usually regarded as a very bad thing. This is not a problem if no one else will base their work on top of your commit.

Parodist answered 26/12, 2016 at 21:21 Comment(5)
I am not sure how this helps? Could you explain the steps, so we and the regular SO user would know what he is doing?Shari
@Shari Kinda late, but added clarification. Still needs some background on git rebase but better than nothing i guess.Parodist
I like this approach. I often end up amending commits I just created, and for some reason I won't go into, our CI tooling has issues when CommitterDate and AuthorDate differ. As a result, I need to keep manually editing the CommitterDate, which is a pain. This solution is nice because I can create an alias that basically does the equivalent of git commit --amend --no-edit without altering the committer date.Ximenes
I just tried this solution and I'm not sure it still works with modern Git. I have 2.35.1 installed and apparently --autosquash only works in interactive rebase. I did find a workaround, by changing the second line to: GIT_SEQUENCE_EDITOR=: git rebase -i --autosquash --committer-date-is-author-date HEAD~2 Then it loads the "rebase interactive" machinery (ie applying the --autosquash option) but then directly applies the rebase instructions without opening a text editor.Ximenes
This method does not update the author of the original commit. Nothing in the commands of the answer corresponds to --reset-author in the question.Seeker
S
5

The mistake is to use --reset-author when using --author like this would suffice:

git commit --amend --author 'My Name <[email protected]>'

As can be seen from the documentation for the options linked above, the option for resetting states:

This also renews the author timestamp.

While the option to merely override the author (available since forever, v1.5.0) does not mention any such side effects.

To modify multiple commits or the entire commit history, the following command may be used:

git rebase -r <commit/branch before wrong author and email or '--root' for all commits> --exec "git commit --amend --no-edit --author 'My Name <[email protected]>'"
Seeker answered 25/3, 2023 at 10:39 Comment(0)
W
1

Most of the answers here were not quite right for what I wanted as I wanted to change the author of an old commit, not a recent one.

WARNING: This will change the author AND committer of every commit that you rebase to your current git user.name and user.email

If you want to change the author AND the committer of one or multiple commits AND preserve the original/historical date of the commit, there is on major caveat: For this to show up correctly in Github.com, you will actually have to rebase every single commit otherwise Github makes it appear like your new commits were as old as the one you rebased.

  1. Ensure the current git author is the one you want to apply to all commits
  2. Select a commit ID BEFORE the commit(s) you want to change the author for
  3. Begin a rebase with git rebase -i <commit_id>
  4. For every commit you edit the line in nano/vim from PICK to EDIT. In vim you can easily do this with :%s/pick /edit /. Then save.
  5. The rebase will stop on every commit and you need to enter a command: export GIT_COMMITTER_NAME=$(git config user.name) && export GIT_COMMITTER_EMAIL=$(git config user.email) && export GIT_COMMITTER_DATE=$(git show --no-patch --format=%aD) && git commit --amend --author="$(git config user.name) <$(git config user.email)>" --no-edit && git rebase --continue
  6. Once you've done this for every commit, the work should be done. Checking in Github.com you should see the old commits have the correct author and the new commits have the new dates, not the old one.

It goes without saying that you should be doing this on a disposable branch to ensure you get the results you're expecting.

Waters answered 29/12, 2023 at 2:14 Comment(0)
G
0

Very similar to @Aleks answer, I found the solution that worked best for me on git-tower:

https://www.git-tower.com/learn/git/faq/change-author-name-email

You set the values for WRONG_EMAIL, NEW_NAME and NEW_EMAIL according to your needs in the following script and run it from within your git project:

git filter-branch --env-filter '
WRONG_EMAIL="[email protected]"
NEW_NAME="New Name Value"
NEW_EMAIL="[email protected]"

if [ "$GIT_COMMITTER_EMAIL" = "$WRONG_EMAIL" ]
then
    export GIT_COMMITTER_NAME="$NEW_NAME"
    export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_AUTHOR_EMAIL" = "$WRONG_EMAIL" ]
then
    export GIT_AUTHOR_NAME="$NEW_NAME"
    export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags

WARNING: This will change the author and email on all the commits where WRONG_EMAIL appears as author.

To quote from https://git-scm.com/docs/git-filter-branch

git filter-branch has a plethora of pitfalls [...]. These safety and performance issues cannot be backward compatibly fixed and as such, its use is not recommended. Please use an alternative history filtering tool such as git filter-repo.

If you still mess up, I hope you know your way around with git reflog. And as @Aleks already said: only do these kind of things on private repos where you work alone.

Gendarmerie answered 28/3, 2022 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.