:bulb: When existing Git history (log) is present, this post covers how to change the commit author and align CommitDate with AuthorDate.

[01] The Two Date Concepts in Git

Every Git commit has two dates.

Item Environment variable Description
AuthorDate GIT_AUTHOR_DATE The date the code was actually written
CommitDate GIT_COMMITTER_DATE The date the commit was recorded in the repository
  • Operations like git rebase, git cherry-pick, and git commit --amend update only CommitDate to the current time, so the two dates can differ.
  • git log’s default output is keyed on AuthorDate, but services like GitHub sort and display commits by CommitDate.

To check both dates of the current commits, use the command below.

1
2
3
4
5
# Show the full log
git log --format='%h  author:%ad  commit:%cd  %s' --date=iso

# Show only the most recent 10 (-n 10)
git log --format='%h  author:%ad  commit:%cd  %s' --date=iso -n 10

Example output:

1
2
a1b2c3d  author:2025-01-02 10:00:00 +0900  commit:2025-03-07 22:14:33 +0900  feat: add login feature
e4f5g6h  author:2025-01-01 09:00:00 +0900  commit:2025-03-07 22:13:10 +0900  init: initial commit

You can see in the example that AuthorDate and CommitDate differ.


[02] Changing the Author

2-1. Change the Author for Future Commits (most common)

To apply the change starting from new commits, set the author info via git config.

(A) Apply to a specific repo only

1
2
git config user.name "New Tester"
git config user.email "newtest@example.com"

(B) Apply globally to every repo of your account

1
2
git config --global user.name "New Tester"
git config --global user.email "newtest@example.com"

Verify after setting:

1
git config --list | grep user

Example output:

1
2
user.name=New Tester
user.email=newtest@example.com

:bulb: Without --global, the setting is stored in the current repo’s .git/config; with --global, it goes to ~/.gitconfig and applies to all repos.


2-2. Fix a Single Commit (–amend)

To change the author of the most recent commit, use --amend.

1
git commit --amend --author="New Tester <newtest@example.com>" --no-edit

Options:

Option Description
--amend Modify the most recent commit
--author="..." Specify the new author name and email
--no-edit Keep the commit message unchanged

Example output:

1
2
3
[detached HEAD a9b8c7d] feat: add login feature
 Date: Thu Jan  2 10:00:00 2025 +0900
 1 file changed, 5 insertions(+)

2-3. Fix Multiple Commits (rebase -i)

git rebase -i lets you interactively select the most recent N commits and change their author. It gives finer range control than filter-branch and suits modifying a small number of commits.

:warning: Rebase rewrites history, so on shared branches always coordinate with teammates before proceeding.

1) Open the rebase todo list (targeting the most recent 8 commits)

1
git rebase -i HEAD~8

2) In the editor, change pickedit for the commits to modify

The editor opens showing the commit list as below. Change pick to edit for the commits whose author you want to change, then save. It is recommended to leave the bottom line (the most recent commit relative to the range, i.e. the oldest in the todo) as pick.

1
2
3
4
5
6
7
8
edit a1b2c3d feat: add search feature
edit e4f5g6h feat: add login feature
edit b7c8d9e fix: typo in README
edit c0d1e2f refactor: clean up utils
edit d3e4f5g chore: update deps
edit f6g7h8i test: add unit tests
edit g9h0i1j docs: update API docs
pick h2i3j4k init: initial commit

3) Each time rebase stops at a commit, run the following in the terminal

1
2
git commit --amend --author="New Tester <newtest@example.com>" --no-edit
git rebase --continue

git commit --amend ... is not typed in the editor — it is a command you run in the terminal after rebase pauses. Running git rebase --continue advances to the next commit; repeat the process for each commit marked edit.

Example output (single commit processed):

1
2
3
4
[detached HEAD a9b8c7d] feat: add search feature
 Date: Thu Jan  2 10:00:00 2025 +0900
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/main.

Options:

Command/Option Description
git rebase -i HEAD~8 Interactively edit the most recent 8 commits
edit Pause rebase at that commit to allow modifications
--amend --author="..." Change the author info of the current commit
--no-edit Don’t modify the commit message
git rebase --continue Continue rebase to the next commit after edits

2-4. Rewrite All History at Once (filter-branch)

:warning: git filter-branch rewrites history, so on shared branches always coordinate with teammates before using it.

Change an author identified by a specific email to a new name/email.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
git filter-branch --env-filter '
OLD_EMAIL="oldtest@example.com"
NEW_NAME="New Tester"
NEW_EMAIL="newtest@example.com"

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

Options:

Option Description
--env-filter '...' Run a shell script per commit to modify environment variables
GIT_COMMITTER_NAME/EMAIL The committer info for CommitDate
GIT_AUTHOR_NAME/EMAIL The author info for AuthorDate
--tag-name-filter cat Rewrite tags as well
-- --branches --tags Apply to all branches and tags

Example output:

1
2
3
Rewrite a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 (2/5) (0 seconds passed, remaining 0 predicted)
Rewrite e4f5g6h7i8j9k0l1m2n3o4p5q6r7s8t9u0v1w2x3 (5/5) (1 seconds passed, remaining 0 predicted)
Ref 'refs/heads/main' was rewritten

Verify the result.

1
2
3
4
5
# Show the full log
git log --format="%H | %an <%ae> | %s"

# Show only the most recent 10
git log --format="%h | %an <%ae> | %s" -n 10

Example output:

1
2
a9b8c7d | New Tester <newtest@example.com> | feat: add login feature
b8c7d6e | New Tester <newtest@example.com> | init: initial commit

git filter-repo is the official replacement for filter-branch — it’s faster and easier to use.

Install:

1
pip install git-filter-repo

Usage:

1
git filter-repo --mailmap mailmap.txt

Example mailmap.txt:

1
New Tester <newtest@example.com> Old Tester <oldtest@example.com>

Example output:

1
2
3
4
5
6
Parsed 5 commits
New history written in 0.08 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at a9b8c7d feat: add login feature
Enumerating objects: 10, done.
Writing objects: 100% (10/10), done.

[03] Align CommitDate with AuthorDate

When CommitDate has drifted to the current time due to a rebase or similar operation, you can align it with AuthorDate.

3-1. Align CommitDate to AuthorDate for the Most Recent N Commits (rebase -i)

When you want to selectively modify a specified range, use git rebase -i.

:warning: Rebase rewrites history, so on shared branches always coordinate with teammates before proceeding.

1) Open the rebase todo (targeting the most recent 8 commits)

1
git rebase -i HEAD~8

2) Change pickedit for the commits to modify, then save

1
2
3
4
edit a1b2c3d feat: add search feature
edit e4f5g6h feat: add login feature
edit b7c8d9e fix: typo in README
pick h2i3j4k init: initial commit

3) Each time rebase stops at a commit, run the following in order

1
2
3
export GIT_COMMITTER_DATE="$(git show -s --format=%aI HEAD)"
git commit --amend --no-edit --date "$(git show -s --format=%aI HEAD)"
git rebase --continue

Repeat the three lines above for as many commits as you marked edit. git commit --amend ... is not typed inside the editor — it is a command you run in the terminal after rebase pauses.

Example output (single commit processed):

1
2
3
4
[detached HEAD a9b8c7d] feat: add search feature
 Date: Thu Jan  2 10:00:00 2025 +0900
 1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/main.

Options:

Command/Option Description
git rebase -i HEAD~8 Interactively edit the most recent 8 commits
edit Pause rebase at that commit to allow modifications
git show -s --format=%aI HEAD Print the current commit’s AuthorDate in ISO 8601 format
GIT_COMMITTER_DATE=... Set CommitDate via a shell environment variable
--amend --no-edit --date "..." Set CommitDate (and AuthorDate) to the specified date, keeping the message
git rebase --continue Continue rebase to the next commit after edits

3-2. Bulk-Sync CommitDate to AuthorDate Across Full History

1
git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE' -- --all

Options:

Option Description
--env-filter '...' Modify environment variables per commit
GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE Set CommitDate equal to AuthorDate
-- --all Apply to every ref in the repo (branches, tags)

Example output:

1
2
Rewrite a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0 (2/2) (0 seconds passed, remaining 0 predicted)
Ref 'refs/heads/main' was rewritten

Verify the result:

1
2
3
4
5
# Show the full log
git log --format='%h  author:%ad  commit:%cd  %s' --date=iso

# Show only the most recent 10
git log --format='%h  author:%ad  commit:%cd  %s' --date=iso -n 10

Example output (after fix):

1
2
a9b8c7d  author:2025-01-02 10:00:00 +0900  commit:2025-01-02 10:00:00 +0900  feat: add login feature
b8c7d6e  author:2025-01-01 09:00:00 +0900  commit:2025-01-01 09:00:00 +0900  init: initial commit

AuthorDate and CommitDate are now identical.


3-3. Change Author and Sync CommitDate in One Pass

Author change and date sync can be handled together inside a single --env-filter.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
git filter-branch --env-filter '
OLD_EMAIL="oldtest@example.com"
NEW_NAME="New Tester"
NEW_EMAIL="newtest@example.com"

if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then
    export GIT_AUTHOR_NAME="$NEW_NAME"
    export GIT_AUTHOR_EMAIL="$NEW_EMAIL"
fi
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then
    export GIT_COMMITTER_NAME="$NEW_NAME"
    export GIT_COMMITTER_EMAIL="$NEW_EMAIL"
fi

export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
' --tag-name-filter cat -- --branches --tags

[04] Pushing to the Remote

Because history has been rewritten, you must push with --force.

:warning: Force push overwrites the remote history, so on branches shared with teammates always coordinate beforehand.

--force-with-lease is a safer force push that rejects the push if someone else has pushed since your last fetch.

1
git push --force-with-lease origin main

Push All Branches and Tags

1
2
git push origin --force --all
git push origin --force --tags

Example output:

1
2
3
4
5
6
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Writing objects: 100% (10/10), 800 bytes | 800.00 KiB/s, done.
Total 10 (delta 2), reused 0 (delta 0), pack-reused 0
To https://github.com/testuser/test-repo.git
 + a1b2c3d...a9b8c7d main -> main (forced update)
Option Description
--force-with-lease Reject the push if the remote has unexpected changes (safer)
--force Overwrite forcibly regardless of remote state
--all Push every local branch
--tags Push tags as well

[05] Cleanup After filter-branch

filter-branch backs up the original commit objects under refs/original/, so once the work is done, clean up with the commands below.

1
2
3
4
5
6
# Remove backup refs
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d

# Clean up unreachable objects
git reflog expire --expire=now --all
git gc --prune=now --aggressive

Example output:

1
2
3
4
5
6
Enumerating objects: 10, done.
Counting objects: 100% (10/10), done.
Delta compression using up to 8 threads
Compressing objects: 100% (8/8), done.
Writing objects: 100% (10/10), done.
Total 10 (delta 2), reused 10 (delta 2), pack-reused 0