如何修改现有的、未推送的提交?描述一种修改尚未推送到上游的先前提交消息的方法。新消息继承原始提交的时间戳。这似乎合乎逻辑,但有没有办法也重新设定时间呢?


当前回答

如果你想获得另一个提交的确切日期(假设你重新编辑了一个提交,并希望它具有原始的预重新编辑版本的日期):

git commit --amend --date="$(git show -s --format=%ai a383243)"

这将更正HEAD提交的日期,使其与提交a383243的日期完全一致(如果有歧义,则包括更多数字)。它还会弹出一个编辑器窗口,以便您可以编辑提交消息。

这是作者日期,这是你通常关心的-查看提交者日期的其他答案。

其他回答

下面是一个方便的别名,它将上一次提交的提交时间和作者时间都更改为date接受的时间——date:

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && GIT_COMMITTER_DATE=\"$d\" \
            git commit --amend --date \"$d\""

使用方法:git cd <date_arg>

例子:

git cd now  # update the last commit time to current time
git cd '1 hour ago'  # set time to 1 hour ago

编辑: 下面是一个更自动化的版本,它检查索引是否干净(没有未提交的更改),并重用最后的提交消息,否则会失败(万无一失):

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && \
        git diff-index --cached --quiet HEAD --ignore-submodules -- && \
        GIT_COMMITTER_DATE=\"$d\" git commit --amend -C HEAD --date \"$d\"" \
        || echo >&2 "error: date change failed: index not clean!"

除了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

两者都可以

在一个命令中处理所有这些建议的更好方法是

LC_ALL=C GIT_COMMITTER_DATE="$(date)" git commit --amend --no-edit --date "$(date)"

这将把最后一次提交的提交日期和作者日期设置为“现在”。

TL;DR:匹配日期+重新创建GPG签名

(如果你知道一个可以保留原始签名的方法,请评论/编辑。)


我将碰到这个旧线程,因为签名提交的特性已经引入,所有这些git过滤器分支和喜欢基本上剥离了文档中指定的签名:

... 如果标签附加了签名,则签名将被剥离。根据定义,不可能保存签名. ...(来源:——tag-name-filter)

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

Afaik,不可能通过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

假设你有一个回购,你想从某个commit(我用根commit;如果其他人负责回购,则不建议使用)。git提交的文档说,如果存在,它也会从env vars中提取数据,因此我们有一个地方可以输入。

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

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

所以我们有:

起点 每次提交的原始日期字符串 GIT_COMMITTER_DATE来匹配日期(author -> committer)

对于重基,我们这样做:

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

(如果您没有用户名。指定签名密钥,使用——gpg-sign=<指纹>)

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

一旦你看到致命:没有调整进度?按Ctrl-C停止循环,检查日志,确认日期匹配,签名无处不在:

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

如果日志中一切正常,只需发出git push——force,就完成了。现在您应该看到每个提交的Verified徽章。

一个真实历史树的例子。GitHub似乎并不关心签名的日期(在任何地方都没有引用),但它仍然会出现在git日志中。

编辑作者日期和最近3次提交的提交日期:

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

——exec命令附加在rebase中的每一行之后,您可以使用——date=…,投稿日期与作者日期一致。