如何在Git中更改旧提交的时间戳?

1111

如何修改已存在但未推送的提交信息?的答案描述了一种方式,可以修改尚未向上游推送的先前提交的消息。 新消息继承原始提交的时间戳。这似乎很合理,但是否有一种方法也可以重新设置时间?


140
git commit --amend --reset-author - Erick M. Sprengel
1
上面的评论^^ (@ErickM.Sprengel) 应该被接受为答案。易于运行,特别是最新提交。 - Wesley Gonçalves
@WesleyGonçalves 这只是一个部分答案。如果你不想将提交时间设置为现在怎么办?你的使用情况并不适用于每个人。 - undefined
30个回答

8

如果您想在标准的Windows命令行中执行被接受的答案(https://dev59.com/T3RB5IYBdhLWcg3w9b19#454750),您需要使用以下命令:

git filter-branch -f --env-filter "if [ $GIT_COMMIT = 578e6a450ff5318981367fe1f6f2390ce60ee045 ]; then export GIT_AUTHOR_DATE='2009-10-16T16:00+03:00'; export GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; fi"

注:

  • 可能可以将命令分成多行(Windows支持使用插入符号^进行换行), 但我没有成功。
  • 您可以编写 ISO 日期,节省寻找正确星期几和一般元素顺序的时间以及由此带来的不必要烦恼。
  • 如果您想让作者和提交者的日期相同,只需引用先前设置的变量即可。

特别感谢 Colin Svingen 的博客文章。尽管他的代码对我没用,但它确实帮助我找到了正确的解决方案。


7
GIT_COMMITTER_DATE="Sun Nov 20 21:02 2022 +0530" git commit --amend --no-edit --date="Sun Nov 20 21:02 2022 +0530"
git push -f

每次都有效。


为什么我们需要两次指定时间? - Franz Wong
1
这是我的猜测:git 中有两个时间戳:提交者日期和作者日期。GIT_COMMITTER_DATE 处理前者,--date 处理后者。 - Ankit Shubham

7

要将最近5次提交的日期更新为当前日期(此方法不允许更新初始提交):

git rebase HEAD~5 --exec "git commit --amend --no-edit --date 'now'"

对于提交记录 95f5074…15074db2 之后的所有提交记录:

git rebase 95f5074…15074db2 --exec "git commit --amend --no-edit --date 'now'"

对于所有提交(包括初始提交):

git rebase --root --exec "git commit --amend --no-edit --date 'now'"

在交互模式下添加-i

运行git log --format=fuller --show-signature以验证更改。

运行git push -f更新远程存储库(⚠️危险区域)

这会有一些影响,例如:

  • 提交ID将发生变化,因此您将不得不重新创建标签
  • 您将失去原始签名
  • 这将使用您的.gitconfig,这意味着如果Git配置为签署提交,则将使用您的密钥来签署提交。

不需要改变最后3个提交的日期,是否有可能用一条命令仅更改第三个提交的 --date 和 env 变量 GIT_COMMITTER_DATE 呢? - the_RR

7

5

编辑最近三个提交的作者日期和提交日期:

git rebase -i HEAD~3 --committer-date-is-author-date --exec "git commit --amend --no-edit --date=now"

--exec 命令会在重新提交的每一行后面添加,你可以使用 --date=... 来选择作者日期,提交者日期将与作者日期相同。


我收到了“致命错误:无法将应用选项与合并选项组合”的提示。 - krubo
Git状态干净吗?命令就是上面那个? - gfdevelop

3

除了Matt Montag的回答之外:

如果您需要在rebase命令后将时间戳重置为当前时间

git rebase -i HEAD~2

你可以使用以下其中一种选项

pick 4ca564e Do something
exec git commit --amend --no-edit --date=now
pick 1670583 Add another thing
exec git commit --amend --no-edit --reset-author

两种方法都可以使用


2

我想确保在午夜准时更新我的代码版权注释,而且不想冒风险使用atcron会有微小的延迟。因此,我提交了代码,然后:

GIT_COMMITTER_DATE="Fri Jan 1 00:00:00 2021 +1000" git commit --amend --no-edit --date="Fri Jan 1 00:00:00 2021 +1000"

(或者甚至将UTC偏移设置为0?决定……)现在我可以推送了!

大家新年快乐。


1

已经有很多好的答案了,但是当我想要在同一天或同一个月更改多个提交的日期时,我找不到合适的答案。因此,我创建了一个新的脚本来解决这个问题,并希望能帮助到某些人:

#!/bin/bash

# change GIT_AUTHOR_DATE for commit at Thu Sep 14 13:39:41 2017 +0800
# you can change the data_match to change all commits at any date, one day or one month
# you can also do the same for GIT_COMMITTER_DATE

git filter-branch --force --env-filter '

date_match="^Thu, 14 Sep 2017 13+"              

# GIT_AUTHOR_DATE will be @1505367581 +0800, Git internal format 
author_data=$GIT_AUTHOR_DATE;                   
author_data=${author_data#@}                  
author_data=${author_data% +0800}                # author_data is 1505367581     

oneday=$((24*60*60))

# author_data_str will be "Thu, 14 Sep 2017 13:39:41 +0800", RFC2822 format
author_data_str=`date -R -d @$author_data`      

if [[ $author_data_str =~ $date_match ]];
then
    # remove one day from author_data
    new_data_sec=$(($author_data-$oneday))
    # change to git internal format based on new_data_sec
    new_data="@$new_data_sec +0800"             
    export GIT_AUTHOR_DATE="$new_data"
fi
' --tag-name-filter cat -- --branches --tags

日期将会被更改:
AuthorDate: Wed Sep 13 13:39:41 2017 +0800

1
我最近需要进行此项工作,制作了一个与git-redate非常相似的脚本。
但是我的脚本只做最少的修改,并且重写(如果需要更新)许多提交所需的时间要少得多,因为它可以一次性处理所有提交。
这是change_git_history,它还允许更改提交消息。
该脚本通过连接许多类似于bash if-expression的语句来实现,以下是用于修改提交日期的语句。
if [ "$GIT_COMMIT" = "$com_hash" ]; # com is commit
then
    export GIT_AUTHOR_DATE="$com_date";
    export GIT_COMMITTER_DATE="$com_date";
fi;

以下是修改提交信息的方式:
if [ true = false ]; # impossible
then
    : # pass
elif [ "$GIT_COMMIT" = "$com_hash" ];
then
    sed 's/.*/$com_msg_esc/g' # replace content with new content
else
    cat - # returns previous content
fi;

我们使用以下方式推送所有更新:

git filter-branch -f \
    --env-filter "$UPDATES" \
    --msg-filter "$MESSAGES" \
    -- "$REV"

(doc is here filter-branch man)


虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。-【来自审查】 - Simas Joneliunas
谢谢@SimasJoneliunas,我已经更新了答案 :) - Xiaojiba

0

概述:日期匹配 + 重新生成 GPG 签名

(如果您知道保留原始签名的解决方法,请在评论/编辑中提出。)


我会顶起这个旧帖子,因为引入了签署提交的功能,所有这些git filter-branch和类似的基本上都按照文档中指定的方式剥离了签名:

... 如果标签附带有签名,则将剥离签名。根据定义,无法保留签名。...(来源:--tag-name-filter

但它也会破坏GitHub提交上漂亮的已验证徽章(如果以相同的方式在其他Git托管位置实现),因此这也将修复它。部分地。

据我所知,无法通过git命令以一种包含提交日期而非签名日期的方式篡改(GPG)签名简单地说。因此,即使作者和提交的日期被更改,它仍将是当前日期,例如:
commit <hash>
gpg: Signature made Sun 25 Jul 2021 00:00:00 PM TZ
gpg:                using TYPE key KEY
gpg: Good signature from "Signer <email@domain.tld>"
Author:     Author <email@domain.tld>
AuthorDate: Sat Jan 1 00:00:00 2000 +0000
Commit:     Author <email@domain.tld>
CommitDate: Sat Jan 1 00:00:00 2000 +0000

假设你有一个 repo,你想要从某个提交签名(我会选择根提交;如果其他人在该 repo 上工作,则不建议这样做)。git commit 文档它也从环境变量中提取数据,如果存在的话,因此我们有一个放置输入的地方。

要检索数据(可以使用 git commit --date=... 设置),我们可以查看 git show --format=%ad,因此对于原始日期字符串,它应该是:

git show --format=%ad --no-patch
# Sat Jan 1 00:00:00 2000 +0000

所以我们有:

  • 起始点
  • 每个提交的原始日期字符串
  • GIT_COMMITTER_DATE 用于匹配日期(作者 -> 提交者)

对于变基,让我们这样做:

git rebase --root <branch-name> --keep-empty --interactive

这将针对分支<branch-name>的根提交进行操作,保留使用git commit -m "empty" --allow-empty创建的任何空提交,并询问您要修改哪些提交。在那里,您将把所需的提交从pick更改为edit(对于我的情况,这将标记所有提交为edit),然后您将进入一个分离的HEAD提交,从这里开始乐趣。

# or "while :"
while true
do
    GIT_COMMITTER_DATE=$(git show --format=%ad --no-patch) \
        git commit --amend --gpg-sign --no-edit --allow-empty
    git rebase --continue
done

(如果您没有指定user.signingkey,请使用--gpg-sign=<fingerprint>

这将遍历每个标记为edit的提交,将提交者的日期设置为与作者的日期相匹配,保留任何空提交,不会触及整体补丁内容,并在执行命令时添加带有日期的签名。

一旦您看到fatal: No rebase in progress?,请按Ctrl-C停止循环并检查日志以确认日期匹配并且签名已经存在于所有地方:

git log --pretty=fuller --show-signature

如果日志中一切正常,只需执行git push --force即可完成。现在您应该看到每个提交的Verified徽章。 具有真实历史树的示例。GitHub似乎不关心签名的日期(没有任何参考),但它仍将出现在git log中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接