【发布时间】:2023-01-10 08:32:48
【问题描述】:
我有一个项目,在不同的地方有一些文件的多个副本。 例如:
src/location1/foobar.h
src/location1/foobar.cpp
src/location2/foobar.h
src/location2/foobar.cpp
我正在将这些提取到自己的库中。 所以我希望结束:
src/location3/foobar.h combining multiple versions of foobar.h
src/location3/foobar.cpp combining multiple versions of foobar.cpp
我已经通过了使用以下方法删除所有不需要的文件的第一个障碍:
git filter-repo --path-glob \*foobar\*
在此过程中发现 filter-branch 最近已被高级 filter-repo 取代(值得重复,因为 filter-branch 仍然出现在此处的许多最佳答案中)。
我现在想将这些副本合并为一个副本,保留它们的所有历史记录。
这两个候选人是merge和merge-file。
merge-file 要求识别每个文件的共同祖先,这可能很痛苦:
src/location3/foobar.h
这在提交历史中是未知的。
我们有 git merge-base 来找到最好的共同祖先。
我不清楚如何为 git merge-file 指定文件版本 我想要做:
git mv src/location1/foobar.h src/newlocation/foobar.h
git commit
git merge-file src/newlocation/foobar.h src/location3/foobar@<commitid> src/location2/foobar.h
...
git merge-file src/newlocation/foobar.h src/location3/foobar@<commitid> src/location3/foobar.h
这是非常费力的,必须对每个文件重复。 另一种方法是创建多个临时分支:
git checkout -b newlibbranch
git mv src/location1/foobar.h src/newlocation/foobar.h
git mv src/location1/foobar.cpp src/newlocation/foobar.cpp
git commit
git checkout oldversion
git checkout -b v2
git mv src/location2/foobar.h src/newlocation/foobar.h
git mv src/location2/foobar.cpp src/newlocation/foobar.cpp
git commit
git checkout newlibbranch
git merge --allow-unrelated-histories v2
这也是相当辛苦的。尽管它可能是可编写脚本的。 还有一个实际问题,因为合并是“重命名/重命名”冲突,而不是实际文件的合并。 这似乎可以通过添加 --allow-unrelated-histories 来解决
所以我的问题是:
关于任务:
- 还有更好的方法吗?也许是一个我不知道的合并工具,就像我不知道 filter-repo
- 我认为多合并分支方式比 git merge-file 更好是正确的吗?
关于合并文件:
- 如何为 git merge-file 指定文件的特定版本
- 是否有自动查找共同祖先的命令或脚本。 就像是:
git merge-file-wrapper location1 location2 --> base = `git merge-base location1 location2` git merge-file location1 $base location2难道这不存在是因为有什么隐患?
【问题讨论】:
-
请注意,Git 没有文件历史。 Git 有提交;提交是历史。每个提交都包含每个文件(进入该提交)的完整快照。 Git 的
git log将通过成对检查提交(一次两个:父项和子项)来伪造合成文件历史记录,以查看两个提交中是否存在特定命名的文件并且具有相同的内容(= 提交无趣) (=提交很有趣)。仅此而已。 -
Git 的
git log确实有--follow,它通过查看每对提交来增强上述内容,以查看文件路径/到/A 是否消失并且新的/路径/B 是否存在具有足够相似的内容来调用它是一个“重命名”。在这种情况下,git log将停止查找旧名称并开始查找新名称。这个技巧非常有限(一次只能查看一个名称)并且在很多情况下都失败了(分支和合并可以伪装重命名,就像更改重命名一样)。 -
git merge-file只是合并工作树文件的命令:必须手动找到要合并的三个文件。除了在.gitattributes设置中自动化之外,它并不意味着真正的工作。git merge基于提交和提交图工作,是真正的合并主力,但它在很大程度上取决于提交图是否正确。对于不相关的历史,图表永远不会正确。 -
我已经回答了我自己的问题,这可能会使我想问的问题更清楚。