This question already has answers here:
How to move files from one git repo to another (not a clone), preserving history
(16个回答)
3年前关闭。
我有两个git存储库,分别是A和B,都包含一个名为file1.cc的文件。
是否可以将存储库A中的file1.cc的历史记录 merge/复制到存储库B中的file1.cc?
问题是我们已经将文件从存储库A移到存储库B,所有文件的历史记录都丢失了。但是现在,一些开发人员已经开始着手处理repo B并 push 他们的更改。因此,现在我希望将某些文件从存储库A到存储库B的 merge/复制历史记录仅适用于某些文件。有可能这样做吗?还是曾经丢失的文件历史会永远丢失?
请帮忙。提前致谢。
如果 repo 包含大量提交,则可能需要一段时间。如果要发送给
好吧,希望以某种方式您有想要移植到 repo 协议(protocol)B中的历史记录。
现在,您在 repo B中:
因此,我在这里假设,将 repo A中最后一个
现在,您有三个选择:重新设定父级,重新设定基准或替换
由于我认为最近的历史记录状态比旧的历史记录状态更重要,并且仅添加了旧的历史记录以供引用,因此最安全的方法是将
因此,您可以从https://git-scm.com/docs/git-filter-branch上的
其中
重新设置可能会更简单一些(假设历史记录之间保持一定程度的一致性),但是可能会导致您最终在
其中
然后删除
这些选项中的任何一个都将重写commit
如果要避免重写,可以使用第三个选项:
因此,要支持此功能,您只需标记
(其中
当有人克隆存储库时,他们只会看到新的历史记录,但是他们可以说
这将记录历史的突破。
完成父项,重新设置基础或替换后,您可以删除
(16个回答)
3年前关闭。
我有两个git存储库,分别是A和B,都包含一个名为file1.cc的文件。
是否可以将存储库A中的file1.cc的历史记录 merge/复制到存储库B中的file1.cc?
问题是我们已经将文件从存储库A移到存储库B,所有文件的历史记录都丢失了。但是现在,一些开发人员已经开始着手处理repo B并 push 他们的更改。因此,现在我希望将某些文件从存储库A到存储库B的 merge/复制历史记录仅适用于某些文件。有可能这样做吗?还是曾经丢失的文件历史会永远丢失?
请帮忙。提前致谢。
最佳答案
可以做到,但可能并不容易。但是首先要注意的是:没有“移动文件的历史记录”。只有移动的提交,因此,如果您想要代表文件子集历史的提交,那么创建这些提交是第一个挑战。
最简单的事情是转移所有历史记录。 (实际上,如果碰巧您将Repo B作为Repo A的浅表克隆,则可以将其浅化并完成。但是我想那不是您创建Repo B的方式...)
无论如何,由于您正从存储库A移至存储库B,因此可能有一些您特别想删除的历史记录。这可能是一个完整的主题,但让我们假设您确实只想要几个文件的历史记录。
在特殊情况下,您想要的所有文件(没有其他文件)都在子目录中,并且您想要(或至少可以接受)将这些文件移动到存储库的根目录中,则可以将filter-branch
与--subdirectory-filter
一起使用。
更一般而言,如果我们假设路径不应更改,并且想要的文件可以在树中的任何位置,则可以将filter-branch
与--index-filter
一起使用。
git filter-branch --index-filter 'git rm --cached --ignore-unmatch each file or *glob* you do NOT want' --prune-empty -- all
如果 repo 包含大量提交,则可能需要一段时间。如果要发送给
rm
的文件列表不平凡,则可能要在 shell 程序脚本中放置多个git rm
命令,并将其用作--index-filter
参数,而不是如上所示对其进行内联。好吧,希望以某种方式您有想要移植到 repo 协议(protocol)B中的历史记录。
cd repo-b
git remote add repo-a path/to/repo-a
git fetch repo-a
现在,您在 repo B中:
... A -- B <--(repo-a/master)
\
(repo-a/other-branches-maybe)
B' -- C -- D (master)(origin/master)
因此,我在这里假设,将 repo A中最后一个
TREE
提交中的master
-我们的历史记录从中重写的那个B
-或至少那棵树的一部分,作为 repo B中的根提交导入。现在,您有三个选择:重新设定父级,重新设定基准或替换
由于我认为最近的历史记录状态比旧的历史记录状态更重要,并且仅添加了旧的历史记录以供引用,因此最安全的方法是将
C
重置为B
。 (您可以选择将B'
改为A
,但我认为这没有太大的区别...)因此,您可以从https://git-scm.com/docs/git-filter-branch上的
filter-branch
文档中提取# be sure you're on master
echo "$commit-id $graft-id" >> .git/info/grafts
git filter-branch $graft-id..HEAD
其中
$commit-id
是B
的SHA,而$graft-id
是C
的SHA重新设置可能会更简单一些(假设历史记录之间保持一定程度的一致性),但是可能会导致您最终在
D
处修改树。如果您决定尝试重新设置基准,那将是git rebase --onto repo-A/master B' master
其中
B'
是存储库B根提交的SHA ID。 (交替git rebase --interactive --onto repo-A/master --root master
然后删除
B'
的条目。)这些选项中的任何一个都将重写commit
C
和D
。 (即使重新 parent 确定TREE
不变,提交仍将被替换。)您的开发人员必须将其视为上游资源库(请参阅“从上游资源库恢复”下的git rebase
文档)。为了减轻这种情况,我通常建议进行协调过渡,在此情况下,开发人员将检查他们拥有的所有内容,丢弃其克隆,然后进行重写,然后从新的仓库中重新克隆它们。如果要避免重写,可以使用第三个选项:
git replace
。已知这有一些怪癖,并且它要求正确设置每个克隆才能“看到”已拼接的历史记录。因此,要支持此功能,您只需标记
B
(也许也可以标记B'
):git tag old-history repo-a/master
git tag new-root B'
(其中
B'
是适当的SHA值ID或等效表达式)。当有人克隆存储库时,他们只会看到新的历史记录,但是他们可以说
git replace new-root old-history
这将记录历史的突破。
完成父项,重新设置基础或替换后,您可以删除
repo-a
Remote 。关于Git:将文件历史记录从一个存储库复制到另一个存储库,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44777043/
10-14 16:56