使用 git-filter-repo 重写并重新提交 git commit-history

使用 git-filter-repo 重写并重新提交 git commit-history

我有一个现有的私有 git 存储库(有两个分支),托管在 GitHub 上。我打算将其公开,但不想公开作者的电子邮件地址。因此,计划是通过将 替换 来重写提交历史,<old-author-email><new-author-email>重新签署提交。另外,我想保留时间戳(这对我很重要!)。

因此,基于广泛的研究,我提出了以下步骤:

  1. 在我的本地机器上克隆存储库。
  2. 创建一个 python-3.x 虚拟环境,并运行pip install git-filter-repo。(来源
  3. .mailmap在存储库中创建一个文件WORKING_DIR,其中包含电子邮件重新映射信息。(来源
  4. 跑步git-filter-repo --force --mailmap .mailmap。 (源1来源2
  5. 以某种方式辞去新承诺!
  6. 然后运行git push origin <your_branch_name> --force,以重写远程提交历史记录。(来源
    • 如果这一步不起作用,我就会直接删除原来的 Github 存储库;创建一个同名的新存储库,然后将本地存储库推送到该存储库。

上述步骤(直到步骤 4),重写作者电子邮件并重新计算哈希值,但丢弃签名。文档中说:(来源

由于 git filter-repo 调用 fast-export 和 fast-import 来完成大量繁重的工作,它继承了这些系统的局限性……提交被重写意味着它们将具有新的哈希值;因此,提交和标签上的签名无法继续工作,而是被删除(因此签名的标签变为带注释的标签)

因此,为了撤销提交,我发现了以下方法(来源)。

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

git filter-branch不建议使用(来源),甚至 Git 自己的文档(来源)。

问题

  • 并且,有没有办法重写作者电子邮件并重新签署新的提交,全部使用git-filter-repo
  • 如果没有!那么,如何在整个提交历史中重写作者电子邮件并重新提出新的提交?(比我的方法更好!)

答案1

如果存储库有多个分支,则此方法无效。因此,在开始之前,请根据您的要求将所有辅助分支合并到主分支(通常为master/ main)。然后删除所有辅助分支。(本地和远程存储库中均有)

我想到了一个可能的解决方案:

  1. 在我的本地机器上克隆存储库。
  2. 创建一个 python-3.x 虚拟环境,激活它,然后运行pip install git-filter-repo GitPython
  3. cd <repo-directory>/../即本地存储库的直接父目录WORKING_DIR
  4. 运行以下 python 脚本:这将.mailmap在 之外创建一个文件,<repo-directory>其中包含出现在所述存储库提交历史记录中的所有唯一作者/提交者姓名和电子邮件组合 - 将被替换为 和NEW_NAMENEW_EMAIL(进一步编辑代码以排除某些名称/电子邮件被重写)
from git import Repo

repo_path = '<repo-directory>'
repo = Repo(repo_path)

commits_list = list(repo.iter_commits())
unq = set()
for cmt in commits_list:
    unq.add((cmt.committer.name, cmt.committer.email))
    unq.add((cmt.author.name, cmt.author.email))

NEW_NAME = "<new-author-name>"
NEW_EMAIL = "<new-author-email>"

lines = list()
for c in unq:
    lines.append(f"{NEW_NAME} <{NEW_EMAIL}> {c[0]} <{c[1]}>\n")

with open(".mailmap", "w") as f:
    f.writelines(lines)
  1. cd <repo-directory>,然后运行git-filter-repo --mailmap ../.mailmap。--> 运行此命令,由于某种原因,似乎删除了remote存储库链接,即git remote -v没有返回任何内容。
  2. 要重置存储库的远程,请运行git remote add origin <remote-repo-url>
  3. 不要这样做:如果你有多个分支要签署提交,请运行git filter-branch --commit-filter 'git commit-tree -S "$@";' HEAD。此外,您可能必须添加一个-f标志才能使其工作。对于分支单独运行,即您需要签出到每个分支并运行所述命令。
    • 执行上述步骤后,我运行git fsck --full --strict后没有出现任何错误。所以,我认为它运行良好!
    • 但是有没有更好的方法来检查存储库的完整性?
  4. 最后,运行git push origin <primary-branch> --force以使用更新的提交历史覆盖所有远程分支。

相关内容