如何修改 Git 提交的历史时间

有时候需要回头修改已有提交的时间:开发机时区配错了,几十个提交全部偏了 8 小时;或者服务器时间没同步,提交时间跑到了未来;又或者一晚上补交的几个 commit 全挤在同一分钟里,想让它们看起来分布得自然一些。

git commit 时可以用 --date 指定时间,但对已经存在的提交,事情要绕一点——因为一个 commit 其实有两个时间

一、关键前提:两个时间

名称 含义 格式占位符 相关环境变量
Author Date 作者时间,代码是什么时候写的,git log 默认显示的就是它 %ad GIT_AUTHOR_DATE
Committer Date 提交时间,这个提交对象是什么时候生成的 %cd GIT_COMMITTER_DATE

正常提交时两者相同,所以平时感觉不到区别。但只要发生 rebase、cherry-pick、amend,Git 就会保留原来的 author date、刷新 committer date,两者就分开了。

用下面这条命令可以把两个时间一起看到:

1
git log --pretty=format:'%h | author: %ad | committer: %cd | %s' --date=iso

只改其中一个,会让两者不一致——git log 显示的是你想要的时间,但仓库里实际排序、以及各托管平台的时间线和贡献图可能仍按另一个走。不同平台取哪个时间的实现并不统一,与其纠结,不如两个一起改。下面所有方法都是成对设置的,原因就在这里。

时间格式推荐 ISO 8601 带时区,例如 2026-07-20T09:00:00+08:00。带上时区可以避免 Git 按本机时区去猜,跨机器操作时结果才稳定。

⚠️ 改历史会让 commit hash 全部变化,被改的提交及其后面的所有提交都会得到新的 SHA。已推送到远端的分支需要 git push --force-with-lease;如果有其他人基于该分支工作,改写前务必先沟通。另外,原本有 GPG 签名的提交在改写后签名会失效,需要重新签名(在 amend / rebase 时加 -S)。

二、方法一:只改最后一次 commit

最简单的场景,直接 --amend

PowerShell:

1
2
3
4
$d = "2026-07-22T15:45:00+08:00"
$env:GIT_COMMITTER_DATE = $d
git commit --amend --no-edit --date=$d
Remove-Item Env:GIT_COMMITTER_DATE

Bash:

1
2
d="2026-07-22T15:45:00+08:00"
GIT_COMMITTER_DATE="$d" git commit --amend --no-edit --date="$d"

要点:

  • --date 只管 author date,committer date 必须靠环境变量 GIT_COMMITTER_DATE,这是最容易踩的坑;
  • --no-edit 表示不修改提交信息,不加会弹出编辑器;
  • PowerShell 里设完环境变量记得 Remove-Item Env:... 清掉,否则同一个会话里后续的提交都会被钉在这个时间上。

三、方法二:交互式 rebase(最通用)

要改最近 N 次提交,而且每次的时间都不一样,用交互式 rebase:

1
git rebase -i HEAD~3

编辑器里把三行的 pick 改成 edit

1
2
3
edit 8063c98 feat: commit number 3
edit 81f0082 feat: commit number 4
edit 653cf29 feat: commit number 5

保存退出后,rebase 会在每个提交处停下来。在每一站执行一次下面的命令(每次换成对应的时间):

1
2
3
d="2026-07-20T09:00:00+08:00"
GIT_COMMITTER_DATE="$d" git commit --amend --no-edit --date="$d"
git rebase --continue

重复三次,直到 rebase 结束。中途想放弃就 git rebase --abort,仓库会回到操作前的状态。

要点:

  • HEAD~3 表示「从倒数第 3 个提交的父提交开始」,也就是要改的是最近 3 个;
  • 如果这三个里包含仓库的第一个 commitHEAD~3 根本不存在,需要改用 git rebase -i --root
  • rebase 期间随时可以 git status 看当前停在哪一站。

四、方法三:filter-branch 批量改

不想一站一站地手动敲,可以用 filter-branch 一条命令按 SHA 分派不同时间。

先拿到完整 SHA:

1
git log --format='%H %s' -3

再执行(在 Git Bash 下运行):

1
2
3
4
5
6
7
8
9
10
11
12
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f --env-filter '
case "$GIT_COMMIT" in
8063c98a6987ef881e4d54ce59d7451cd43b2d8e) D="2026-07-20T09:00:00+08:00" ;;
81f0082bdccf5e85c66410df3479ba3809f6b669) D="2026-07-21T10:30:00+08:00" ;;
653cf2959caa337b08a36863b211dd40bb9972a5) D="2026-07-22T15:45:00+08:00" ;;
*) D="" ;;
esac
if [ -n "$D" ]; then
export GIT_AUTHOR_DATE="$D"
export GIT_COMMITTER_DATE="$D"
fi
' HEAD~3..HEAD

要点:

  • case 里必须写完整的 40 位 SHA$GIT_COMMIT 是全长的,短 hash 匹配不上,会静默地什么都不改——这是最常见的失败原因;
  • 末尾的 HEAD~3..HEAD 限定只处理最近三个提交,不加会遍历整个历史,又慢又没必要;
  • --env-filter 的内容是一段 sh 脚本,Windows 上请用 Git Bash 执行,PowerShell 的引号规则会和它冲突;
  • FILTER_BRANCH_SQUELCH_WARNING=1 用来屏蔽 Git 关于 filter-branch 已不推荐的告警。

Git 官方推荐用 git-filter-repo 替代 filter-branch,但它需要额外安装。只改少量提交时,filter-branch 已经够用了。

五、方法四:给多个 commit 设置同一个时间

如果这几个提交要用同一个时间,有更短的写法:

1
2
3
export GIT_COMMITTER_DATE="2026-07-20T09:00:00+08:00"
git rebase HEAD~3 --exec 'git commit --amend --no-edit --date="2026-07-20T09:00:00+08:00"'
unset GIT_COMMITTER_DATE

要点:

  • --exec 会对范围内每个提交执行同一条命令,所以时间必然相同,无法逐个区分;
  • 它走的是 rebase 的机制,但不会打开编辑器,全程无交互;
  • 同样地,它不会自动改 committer date,需要提前 export GIT_COMMITTER_DATE

六、改坏了怎么回滚

改历史之前最好先记一下当前的 commit hash,或者直接打个临时分支 git branch backup-before-rewrite。万一没记,也还有退路。

filter-branch 之后

filter-branch 会自动留下备份 ref:

1
git reset --hard refs/original/refs/heads/main

确认改动无误后再清理备份:

1
git update-ref -d refs/original/refs/heads/main

注意:备份 ref 还在的时候,再次运行 filter-branch 需要加 -f,否则会报错拒绝执行。

rebase / amend 之后

查 reflog 找到操作前的位置:

1
2
git reflog
git reset --hard HEAD@{5} # 换成 rebase 之前那条

reflog 默认保留 90 天,所以只要没有手动 git gc --prune,改写前的提交都还能找回来。

七、方法对比

方法 适用场景 是否需要交互 能否每个 commit 不同时间
--amend 只改最后一次
rebase -i 最近 N 次,逐个改
filter-branch 批量、可脚本化
rebase --exec 批量设成同一时间

小结

三条经验:

  1. 两个时间一起改--dateGIT_COMMITTER_DATE,只改一个必然留下不一致;
  2. 先想清楚范围,只动最后一个就用 --amend,动 N 个就限定 HEAD~N..HEAD,别让工具去遍历整个历史;
  3. 改的是共享分支就先打招呼,force push 之后别人的本地分支会对不上,这个沟通成本远高于改时间本身。

如何修改 Git 提交的历史时间
http://eevann.cn/2026/07/25/git-modify-commit-time/
作者
月下独白
发布于
2026年7月25日
许可协议