重新规范化 git 历史记录

Renormalize git history

我正在尝试重新规范化我的 git 历史记录中的行结尾。我想这样做,因为这个 repo 是从一个带有 git-tfs 的 tfs repo 创建的,并且有多个提交带有混乱的行尾。

为什么 git rebase --root --strategy renormalize master 如果我已经将 .gitattributes 文件重新定位到第一个包含 * 的提交中,为什么不更正提交中的行结尾文本=自动?

Rebase 复制提交,但它有局限性。最大的一个是它字面上 不能 复制任何合并提交。现代 Git(最近一两年内)已经获得了 --rebase-merges 标志,更接近了,但仍然不可能 复制 合并。所以在这里,Git 将 重新执行 合并。

可能 已经足够好了 — 但仍然存在问题。即使新的初始提交中包含所需的 .gitattributes(在这种情况下,您可以同时转换该提交的 内容 ,因此不需要 --root), 当 rebase 执行提交复制时,它不一定规范化每个文件的行结尾。例如,假设我们有这个小迷你图:

A--B--C   <-- master

您可以使用 git switch --orphan new-master 准备创建一个新的根提交,然后读出提交的内容 A,添加 .gitattributes,规范化所有工作的行尾树文件及其索引副本,并提交,以获得新的提交 A':

A--B--C   <-- master

A'  <-- new-master (HEAD)

到目前为止,我们的状态很好。现在我们 运行 git cherry-pick master~1,这就是 git rebase 将提交 B 复制到新提交 B' 的操作。在 AB 之间,一些文件被修改,因此 Git 将对这些文件的修改复制到您的索引和工作树中,并强制它重新规范化这些文件的行尾以处理任何使更改适合所需的修复。但是 B 还添加了一个全新的文件,其行尾不正确匹配。由于此 new 文件在 AA' 中都没有对应的文件,因此 Git 可以——而且我认为会,尽管你必须这样做对其进行测试以确保确定——只需将其全部复制而不重新规范化 行结尾。

Git 会为 B-vs-C 重复此操作;同样,任何全新的文件都不会被重新规范化。所以你最终得到:

A--B--C   <-- master

A'-B'-C'  <-- new-master (HEAD)

其中自 A 以来引入的文件在某些​​提交中可能没有正确的行结尾。

如果由 rebase 制作的副本被 重新规范化,我们只剩下合并问题了。如果您不介意重新执行合并——这可能需要您重新解决任何合并冲突——那么这个整体策略应该有效。

但是,还有另一种方法可以做到这一点。您可以使用 git filter-branch 或其现代(但尚未与 Git 一起分发)替代品 git filter-repo,而不是使用 rebase。它们都能够进行每个原始提交——包括合并——并在进行之前对原始提交中的每个文件应用“内容过滤器”新提交。

您想要的内容过滤器是:

  • 添加.gitattributes,然后
  • 重新归一化

filter-branch 过滤器不是特别擅长这个,但你肯定它(可能,最慢的过滤器,--tree-filter,会工作此处框:将 /tmp/.gitattributes 复制到 ./.gitattributes 的树过滤器可能就足够了)。 filter-repo 命令正在积极开发中,您可以请求“添加属性并重新规范化”命令行选项,因为这似乎是人们现在想要做的更多事情。