【发布时间】:2021-05-29 01:14:23
【问题描述】:
我正在尝试重新规范化我的 git 历史记录中的行尾。我想这样做,因为这个 repo 是使用 git-tfs 从 tfs repo 创建的,并且有多个提交的行尾混乱。
如果我已经将 .gitattributes 文件重新设置为包含 * text=auto 的第一个提交,为什么 git rebase --root --strategy renormalize master 不能更正提交中的行尾?
【问题讨论】:
我正在尝试重新规范化我的 git 历史记录中的行尾。我想这样做,因为这个 repo 是使用 git-tfs 从 tfs repo 创建的,并且有多个提交的行尾混乱。
如果我已经将 .gitattributes 文件重新设置为包含 * text=auto 的第一个提交,为什么 git rebase --root --strategy renormalize master 不能更正提交中的行尾?
【问题讨论】:
变基复制提交,但它有局限性。最大的问题是它确实无法复制任何合并提交。现代 Git(在过去一两年内)已经获得了 --rebase-merges 标志,距离更近了,但仍然无法复制合并。所以在这里,Git 会重新执行合并。
这个可能已经足够好了——但还是有问题。即使新的初始提交中包含所需的 .gitattributes(在这种情况下,您可以同时转换该提交的 contents,因此不需要 --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' 的操作。在A 和B 之间,一些文件被修改了,因此Git 将对这些文件的修改复制到您的索引和工作树中,并且您强制它重新规范这些文件的行尾以处理进行更改所需的任何修复合身。但是B 还添加了一个全新的文件,其行尾不正确匹配。由于这个 new 文件在 A 或 A' 中都没有对应的文件,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 命令正在积极开发中,您可以请求“添加属性并重新规范化”命令行选项,因为这似乎是人们现在想要做的更多事情。
【讨论】: