如何从Git中提取历史记录的子集?

11

更新:我试图简化真实的示例以便清晰地解释我的选项,但那并没有真正起作用。下面链接的示例太过笼统,无法使这个简单的示例工作。

我以前在 SVN 中经常做这种事情,并且变得非常熟练。现在我发现在 Git 中非常困难,开始相信我的历史记录基本上已经混合在一起,无法分开。

现实世界中的问题:我有大约十几个文件被移动和重命名。它们的历史记录与数百个其他文件的历史记录交织在一起,我想完全删除它们的历史记录。

在 SVN 中,我可以使用一系列的 dump/include-filter/exclude-filter/load 来缩小存储库,很少需要在加载之前手动重命名转储文件中的路径。

像这样,我就完成了:

SET Includes=trunk/src/Foo.aaa trunk/src/Foo.bbb trunk/src/Foo trunk/src/Bar
SET Excludes=trunk/src/Bar/Blah.aaa trunk/src/Foo/Blah.aaa

svnadmin dump FooSrc > Full.dump 2> Dump.log
svndumpfilter include %Includes% --skip-missing-merge-sources --renumber-revs --drop-empty-revs < Full.dump > Filter_1.dump 2> Filter_1.log
svndumpfilter exclude %Excludes% --skip-missing-merge-sources --renumber-revs --drop-empty-revs < Filter_1.dump > Filter_2.dump 2> Filter_2.log
svnadmin create FooDest
svnadmin load FooDest --ignore-uuid < Filter_2.dump > Load.log 2> Load_Errors.log

有没有人有一个好的例子,不仅仅是简单地删除单个文件或导出单个子目录的示例?

我能想到最简单的定义文件集的方法是使用7个目录路径列表。那些目录中的所有内容都需要保留,而在外面的内容需要从历史记录中剪切掉。


简化的问题:

我有一个 Git 仓库,其中有一些文件,我想将它们提取到自己的仓库中。问题是这些文件在原始仓库的历史中创建和修改,因此我很难找到一个干净的提取方法。

以下是我的历史记录的梗概(只是更多的提交和要忽略的东西)。正如您所看到的,显然我没有计划以后从历史记录中挑选这些文件:

commit 4a09d3f977a8595d9e3f61766a5fd743e4265a56

M    src/Foo/Bar/FileToExtract2.foo
A    src/Foo/Bar/FileToExtract3.bar
D    src/Foo/AnotherFileToIgnore.txt

commit 05d26f23518083270cc45bf037ced29bec45e064

M    src/Foo/Blah/IgnoreThisOneToo.foo
M    src/Foo/AnotherFileToIgnore.txt

commit 343187228f4bd8e4427395453034c34ebd9a95f3

M    src/Foo/Bar/FileToExtract1.txt
M    src/Foo/AnotherFileToIgnore.txt

commit 46a0129104ac31291462f657292aab43f8883d8d

A    src/Foo/Bar/FileToExtract1.txt
A    src/Foo/Bar/FileToExtract2.foo
M    src/Foo/FileToIgnore.txt

commit 3fe6af56f0d8dc42fcb5b0bafee41bff534ba2cc

A    src/ReadMe.txt
A    src/IgnoreMe.foo
A    src/Foo/FileToIgnore.txt
A    src/Foo/Blah/IgnoreThisOneToo.foo
A    src/Foo/AnotherFileToIgnore.txt
最终,我希望拥有一个干净的存储库,其中仅包含src/Foo/Bar/目录下的文件的完整历史记录。其余内容可以忽略。如果不修改历史记录,仅提交一个删除整个目录的操作也是可以接受的。
在SVN中,我会使用svnadmin dumpsvndumpfiltersvnadmin load命令。如果小心谨慎,甚至可以手动编辑转储文件以清理路径等内容。
我一直在查找Git命令,但无法找到实现此操作的方法。非常感谢任何帮助。
2个回答

7

@McKAMEY:https://dev59.com/questions/O3M_5IYBdhLWcg3wUxdB 是一个不错的开始:使用子模块或子树合并。 - VonC
啊,我想我明白了。对于每个子目录,都生成一个存储库,然后将它们合并成单一的存储库?历史记录是否交错或者仅是一个接一个地堆叠在一起? - mckamey
@McKAMEY:我相信在使用子树合并时,历史记录是堆叠的。但我确信两个子模块的历史记录仍然是独立的(请参见子模块的真实本质:https://dev59.com/mXI-5IYBdhLWcg3wMFMf#1979194)。不过,在你的情况下,子树合并可能更有意义。 - VonC
1
@McKAMEY:它们是独立的(两个根,即没有父提交)。 - Jakub Narębski
如果提交影响到两个子目录怎么办?这会将这些提交分割成独立的吗? - mckamey
显示剩余4条评论

3

@VonC:感谢您提供链接。 - Jakub Narębski
我有7个目录,其中包含我需要提取的所有文件列表。在导出和导入之间,我需要指定什么来过滤除这7个目录以外的所有内容?我需要等同于“svndumpfilter include”的功能。 - mckamey
“查看示例”链接仅提供一个sed "s|refs/heads/master|refs/heads/other|"过滤脚本的示例。我该如何告诉Git删除所有不存在于我的7个子目录之一中的文件? - mckamey

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