Git:将文件的历史记录从一个存储库复制到另一个存储库

时间:2017-06-27 09:42:03

标签: git

我有两个git存储库说A和B,都包含一个名为file1.cc的文件。 是否可以将repo A中file1.cc的历史合并/复制到repo B中的file1.cc?

问题是我们已经将文件从回购A移动到回购B并且所有文件的历史记录都丢失了。但现在一些开发人员已经开始研究回购B并推动了他们的改变。所以现在我想要从repo A到repo B的一些文件的合并/复制历史记录,这些文件仅适用于某些文件。有可能这样做吗?或者一旦丢失的文件的历史将永远丢失?

请帮忙。提前谢谢。

1 个答案:

答案 0 :(得分:12)

可以做到,但可能并不容易。但首先要做的事情是:没有"移动文件的历史记录"。只有移动提交,所以如果你想要提交代表文件子集历史的提交,那么创建这些提交是第一个挑战。

最简单的方法是转移所有历史记录。 (事实上​​,如果碰巧你将Repo B作为Repo A的浅层克隆,那么你可以解开它并完成它。但是我猜测那并不是你如何创建Repo B ...)

无论如何,既然您已经从Repo A转到Repo B,那么您可能还有一些特别想要删除的历史记录。这可能是它自己的一个完整主题,但让我们假设你真的只想要几个文件的历史。

在特殊情况下,您想要的所有文件(没有其他文件)都在子目录中,并且您希望(或者至少可以接受)将这些文件移动到repo的根目录,可以将filter-branch--subdirectory-filter一起使用。

更一般地说,如果我们假设路径不应该更改并且您想要的文件可以在树中的任何位置,那么您可以使用filter-branch {{1} }}

--index-filter

如果repo有很多提交,那可能需要一段时间。如果git filter-branch --index-filter 'git rm --cached --ignore-unmatch each file or *glob* you do NOT want' --prune-empty -- all 的文件列表不重要,您可能希望在shell脚本中放置多个rm命令,并将其用作git rm参数,而不是如上所示内联它。

嗯,不管怎样,希望你有一段历史,你想要嫁接到Repo B。

--index-filter

现在你有回购B:

cd repo-b
git remote add repo-a path/to/repo-a
git fetch repo-a

所以我在这里做了一个假设,来自Repo A中最​​后一次... A -- B <--(repo-a/master) \ (repo-a/other-branches-maybe) B' -- C -- D (master)(origin/master) 提交的TREE - 我们的历史记录重写创建的master - 或者该树中至少有一部分是作为Repo B中的根提交导入的。

现在您有三个选项:re-parent,rebase或replace

由于我假设最近的历史状态比旧历史状态更重要,并且旧的历史记录只是被添加以供参考,最安全的事情是将B重新定位到C 。 (您可以选择将B重新表示为B',但我认为这并没有太大区别......)

所以从https://git-scm.com/docs/git-filter-branchA文档中抽取你可以

filter-branch

其中# be sure you're on master echo "$commit-id $graft-id" >> .git/info/grafts git filter-branch $graft-id..HEAD $commit-id的SHA而B$graft-id

的SHA

rebase可能稍微简单一些(假设历史之间具有一定程度的一致性),但引入了最终修改C树的可能性。如果你决定尝试一个rebase,它将是

D

其中git rebase --onto repo-A/master B' master 是Repo B root commit的SHA ID。 (可替代地

B'

然后删除git rebase --interactive --onto repo-A/master --root master 的条目。)

这两个选项中的任何一个都会重写提交B'C。 (即使重新父母确保D未更改,仍然会替换提交。)您的开发人员必须将其视为上游rebase(请参阅&#34下的TREE文档;从上游变种&#34;)。为了缓解这种情况,我通常建议做一个协调的切换,让开发人员检查他们拥有的所有内容,丢弃他们的克隆,然后你进行重写,然后从新的repo重新克隆。

如果您想避免重写,可以使用第三个选项:git rebase。众所周知这有一些怪癖,它要求每个克隆都要正确设置,以便&#34;看到&#34;拼接的历史。

为了支持这一点,您只需标记git replace(也可能B):

B'

(其中git tag old-history repo-a/master git tag new-root B' 是适当的SHA值ID或等效表达式。)

当有人克隆回购时,他们只能看到新历史,但他们可以说

B'

这将记录历史上的突破。

完成重新定位,变基或替换后,您可以删除git replace new-root old-history 遥控器。