首页 > 解决方案 > 是否可以轻松地从两个不同的分叉存储库更新您自己的存储库文件,而无需从分叉中提取所有内容?

问题描述

为了解释我正在尝试做的事情,我使用了关于 GitHub 存储库的书类比:

假设我有两本书,我想从这两本书中取出一些页面并将这些页面放入一本大书中。然后我希望每次有人更新原始书籍时更新我所使用的页面。就像如果有人在我选择添加到我的书中的页面上写了一些新的东西,他们的新文本会出现在我自己的页面中。

我尝试过使用模块,但看起来这需要我将整个 repo 复制并更新到我自己的 repo 中,而不是仅仅更新我想要的特定文件。

标签: gitgithub

解决方案


我不知道你打算用你的比喻去哪里,但我认为这并不重要。简短的回答是“不”,原因很简单:Git 与文件无关。Git 真的是关于提交

(但其中一些可能取决于“拉动一切”的意思。)

提交确实包含文件,当我们使用一些 Git 存储库时,我们可能关心文件。但 Git 不会:它关心commits。它的基本存储单元是提交。它的许多操作都是通过提交进行的——包括所有将事物从一个 Git 转移到另一个 Git 的操作。即使是可以处理文件的命令也大多是1将文件从工作区复制到 Git 的index,或从索引复制到工作区 ...并且 index 可能最好将其总结为建议的 next commit

所有这一切的结果是可以随心所欲地处理文件,但Git喜欢将所有这些文件放入一个新的快照(提交)中,然后处理提交。如果您想从两个 GitHub 存储库 A 和 B 中获取内容,则必须使用git fetch两个 URL,指向这两个存储库,以使用来自 A 和 B 的任何新提交填充您的本地 Git 存储库。

这是否构成“拉动一切”取决于您对“拉动一切”的定义。请注意,您不会使用git pull来实现此状态,因为这意味着fetch,然后是 merge。合并将合并提交,这可能不是您想要的。为了达到这个状态,你可以从 A 和 B 获得最新的,你只需使用git fetch两次:一次从 A 获取最新的,一次从 B 获取最新的。

现在的问题变成了:提交不仅仅是文件的快照;它还记得其直接前任的原始哈希 ID,Git 将其称为提交。由于每个提交都会记住它的父级,Git 总是可以从某个提交序列中的最后一个提交开始,并向后工作:带有 hashH的提交在带有 hash 的提交之前G。从G,Git 找到FE然后找到D,以此类推,一直回到第一次提交。

那么,Git 存储库中的历史就是提交。它是从末尾开始形成的提交链(哈希 ID 以某个名称存储的提交)并向后工作。如果您从所有分支名称开始,然后向后工作,您将获得所有分支历史记录:

                I <-J  <--branch1 (HEAD)
               /
... <-F <-G <-H
               \
                K <-L  <--branch2

运行git merge告诉你的 Git:使用这些向后箭头形成的历史记录来查找两个或多个分支之间的共同提交。 例如,通过上述方式,提交JL到达一个共同的共享点H然后,找到共同的共享提交后,比较三个提交中的快照,以便我们看到我在 上更改了branch1什么,以及他们在 上更改了什么branch2。也就是说,H对我的 diff 提交J,然后分别H对他们的L. 然后,结合差异并M从组合结果中进行新的提交。由于我的分支是branch1,请更新名称branch1,使其指向这个新的合并提交。

如果一切顺利,结果是:

       I--J
      /    \
...--H      M   <-- branch1 (HEAD)
      \    /
       K--L   <-- branch2

其中的快照M是从 获取所有文件H、应用从Hto看到的所有更改J、应用(删除冗余)从Hto看到的所有更改L并提交结果文件集的结果。(所以在这里,Git对文件进行操作——但总是对一完整的文件进行操作,来自三个单独的提交!重要的是提交;文件仅在提交由它们构成的范围内才重要。)

由您决定是否以及如何考虑git merge其他一些内部 Git 操作(其中大部分操作在提交上)可能对您的最终问题真正有用。Git在这里只是一组工具,而不是解决方案。事实上,对于几乎所有的问题,Git 都不是一个解决方案,它只是一个工具集。


1特别是,或者首先从您刚刚选择的提交中填充索引,然后替换工作树文件,以便它们与索引中的副本匹配。这样,您刚刚签出的当前提交与索引中建议的下一个提交匹配,可以看到所有文件,这些文件现在在您的工作树中采用普通的日常文件格式。该命令将您可能刚刚更新的文件从工作树复制到索引中的特殊 Git 格式版本,准备进入下一次提交。git checkout branchgit checkout hashgit add file

“大部分”这个词需要在这里,因为git checkout它有一些专门的子模式,你可以git show从单个提交中单个 blob 对象,等等。


推荐阅读