有没有一种方法可以对所有以前的提交进行gpg签名?

50
如标题所述,我正在寻找一种方法来对存储库中所有以前的提交进行gpg签名(最好不需要为每个提交输入我的密码)。

1
这里有一个旧的超级用户帖子,其中有一些回答这个问题。 - PatrickSteele
有没有办法使用 filter-branch 或类似的工具自动完成这个过程?那些解决方案需要我去交互式地重新设置,这样会让我去操作一些东西。 - pradyuman
4
一个提交取决于所有先前的提交。因此,如果您签署一个提交,您隐含地签署了导致该提交的所有历史记录。 - G. Sliepen
2
我在这里同意@G.Sliepen的观点,但我还要补充一点,即有一些理论方法可以破解SHA-1,在某些尚不太可能的情况下,攻击者可能会替换一些中间历史提交,从而破坏Merkle哈希链保证,即签署后续提交隐含地涵盖了所有较早的提交。换句话说,理论上每个提交都进行GPG签名更安全。实际上,这并不值得担心。 - torek
这个回答解决了你的问题吗?使用GPG签署现有提交 - chalasr
请参阅超级用户讨论中的答案 Can you GPG sign old commits? - Michael Freidgeim
4个回答

71

我的方法是

git rebase --exec "git commit --amend --no-edit -n -S" -i 8fd7b22

8fd7b22之后开始的所有提交将被重新打基础,除了签名外没有任何更改。如果要更改从第一个提交开始的所有提交,您可以使用--root(自Git v1.7.12起):

git rebase --exec "git commit --amend --no-edit -n -S" -i --root

为了将更改传播到远程,我使用

git push --force

注意,这将更新“gpg made”日期时间,例如,GitHub将把它视为提交日期。Git本身会保留原始日期和新日期,git log --show-signature可以清楚地显示原始提交的时间以及最后一次签名的时间。


4
虽然这种方法可行,但我想补充一点,它会破坏实际的提交日期。@dhilt,你应该在回答中考虑加上这一点。因此,不是“没有更改”,只是签名。 - roshnet
@sansari 很好的问题!我更新了答案,提供了解决方案(--root)。 - dhilt
@dhilt 添加根会拉取整个历史记录,而不仅仅是当前分支。 - sansari
1
@sansari 使用 --root [<branch>] 语法来指定分支,请参考 git-rebase 文档 - dhilt
1
在Windows shell(例如cmder)中,您可能需要将单引号更改为双引号。 git rebase --exec“git commit --amend --no-edit -n -S” -i 8fd7b22 参见https://superuser.com/questions/1656806/why-git-commit-doesnt-recognize-amend-on-git-windows - Michael Freidgeim
显示剩余5条评论

45

您可以这样做,但这将需要重写您的整个历史记录。

签署提交会更改提交并更改其提交ID。由于提交ID依赖于以前的提交ID,因此之后的所有提交都必须更改。而且您已经为它们全部签名了。

如果它是没有其他合作者在使用的个人存储库,则不是问题。如果它是有其他合作者的存储库,请像进行重大变基一样处理。

您可以使用git filter-branch并加上-S选项来重新进行每个提交。

git filter-branch --commit-filter 'git commit-tree -S "$@";' -- --all

不需要为每个提交输入密码,您需要配置 gpg 使用 gpg-agent。如果您熟悉 ssh-agent,这是一个类似的想法,它是一个小进程,您只需向其提供一次密码,它就会将其存储在内存中。如何进行配置取决于您的操作系统和设置。在 OS X 上,我让GPG Tools 来处理它。


2
感谢您的帮助! - pradyuman
2
这个很好用,谢谢。如果能解释一下filter-branch命令就更好了——我对commit-treefilter-branch都不熟悉,所以这看起来像魔法。 - taylorthurlow
1
当我运行命令时,出现以下错误:错误:gpg无法签署数据,无法编写重写提交 - David DeMar

10

如果您想筛选特定的提交并仅对它们进行签名,您可以使用 filter-branch 命令:

git filter-branch --commit-filter 'if [ "$GIT_COMMITTER_EMAIL" = "user@domain.com" ];
  then git commit-tree -S "$@";
  else git commit-tree "$@";
  fi' HEAD

如果出于某种原因,您只想签署自己的提交记录,则这很有用。


3

我想要解决的用例是在保留原始提交日期的同时,签署我之前的所有提交。

签署相关提交

git rebase -i --root
git commit --amend -S --no-edit &&  git rebase --continue # for all the relevant commits

返回提交日期作为作者日期并强制推送(在推送前不要忘记备份)。
git rebase --committer-date-is-author-date -i --root # return 
git push origin main -f

可以使用其他答案自动化。


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