如何让两个已检出的 git 存储库彼此同步?

how do I keep two checked out git repositories synchronize with each other?

我的所有数据都在 git 存储库中的家用 PC 上。

这台家用电脑(以及 git 存储库)只能从家用电脑所在的本地局域网访问。将 git 存储库放在可访问 Internet 的云服务器上,或者让我的家用 PC 可在 Internet 上访问,都不是一种选择。对于下面的问题,这个限制很重要,因为否则显而易见的解决方案是 "just put your git repo on a cloud server".

我有一台随身携带的笔记本电脑,名为 Laptop-A。 在我开始旅行之前,我使用以下方法从我的家用 PC 上查看 Laptop-A 上的存储库: git 克隆 ssh://main-PC/... 在旅行期间,我在 Laptop-A 上进行了本地更改,并在本地提交了它们,但我无法推送它们,因为无法通过互联网访问我家用 PC 上的主存储库。 我的更改只能在 return 在家并且与我的家用 PC 在同一局域网上时才能推送。

一切正常,但现在我在旅行时添加了 Laptop-B。这台笔记本电脑也克隆了主仓库,就像 Laptop-A 一样。事实上,这两台笔记本电脑基本相同,但它们是两台独立的机器。我这样做是为了防止其中一台笔记本电脑出现硬件故障。那样的话,我还有另一台笔记本电脑。

但是,现在我 运行 遇到了一个问题,即两台笔记本电脑确实是多余的,当我对一台笔记本电脑上的 git 存储库进行本地更改时,该更改不会反映出来在另一台笔记本电脑上的 git 存储库中,因为它们显然是两个单独签出的存储库副本。我可以在每台笔记本电脑上手动和单独提交每个更改,但这很尴尬,而且我可能会犯错误导致不一致。即使我做对了,这也很烦人,一旦我想在 return 回家时从两台笔记本电脑上推送,就会导致合并冲突。

我想做的是在 Laptop-A 上提交更改,然后将其同步到 Laptop-B,这样我就可以在 return 回家后从任何一台笔记本电脑推送(到主仓库) .

我怎样才能做到这一点?

没有 Git 存储库比任何其他 Git 存储库 "special" 或 "more important",除非您自己认为如此。

当您 git clone ssh://main-PC/... 在笔记本电脑 A 上时,Git 您 运行 在笔记本电脑 A 上创建一个 Git 存储库,它是一个 对等 [= main-PC 上 Git 的 88=]。你只认为主要的 PC 版本是 "more master-y" 因为你就是这样使用它的,事实上,在旅行时,笔记本电脑版本是 "more master-y" 因为它有新的提交。

您的 laptop-A 存储库使用名称 origin 来记住 URL ssh://main-PC/...。名字 origin 是一个 远程 。您的笔记本电脑 A Git 使用 远程跟踪名称 形式 origin/* 来记住其他 Git 中的 b运行ch 名称.

在你的笔记本电脑 B 上,你可以克隆你的笔记本电脑 A 克隆,或者你的主 PC 克隆。您的膝上型电脑 B 会记住您在此处使用的任何 URL its 名称 origin,并使用远程跟踪名称 origin/* 记住 b运行ch 在克隆过程中复制的名称。

您可以向任一笔记本电脑添加更多远程 名称。例如,假设笔记本电脑 A 和 B 都是 运行 git clone ssh://main-PC/...,因此在两者上,origin 表示 ssh://main-PC/...,您可能希望在笔记本电脑 A 上执行此操作:

git remote add laptop-b ssh://ip.address/path/to/repo.git
例如

(当然 IP 地址可能会随着时间的推移而改变,因此您需要删除并重新添加,或使用 git remote set-url 来有时修复它)。现在laptop-A有一个name给laptop-B,你可以git fetchgit push从A到B获取(fetch)或发送(push)任何在 B 但不在 A(获取)或 A 但不在 B(推送)上的提交。同样,在笔记本电脑 B 上:

git remote add laptop-a ssh://ip.address/path/to/repo.git

将在笔记本电脑 B 上创建远程名称 laptop-a,现在您可以 git fetchgit push 使用此名称。

一台笔记本电脑上的提交现在很容易运行转移到另一台笔记本电脑上。请注意,例如笔记本电脑 A 上的 远程跟踪名称 laptop-b/master 是一台笔记本电脑如何记住另一台笔记本电脑有一些提交的方式 - 所以现在您需要让任何笔记本电脑 "behind" 更新其本地 b运行ch 名称以记住新的提交。

关键概念是所有三个存储库都是对等的。 None 具有任何特殊地位,除非您个人认为它具有某种特殊地位。您可以根据记录在 origin/masterlaptop-a/masterlaptop-b/master.

等远程跟踪名称下的提交哈希 ID 来决定,而不是做出静态决定

每个对等存储库中的 b运行ch 名称 是不同的。 提交哈希 ID 是相同的,只要它们都具有相同的提交。当一个存储库缺少一些提交时,git fetch 会将它们拉入(从需要提交的存储库到拥有它们的存储库),and/or git push 将发送它们(从有提交的存储库到需要它们的存储库。

这两个操作——获取和推送——几乎是对称的,除了另一个关键区别。 fetch 操作获取源存储库的 b运行ch 名称并 renames 它们,以便它们进入远程跟踪名称,例如origin/masterpush 操作发送提交,然后:

  • 要求推送的目标设置一些b运行ch名称(这是礼貌的非强制推送),或者
  • 命令推送的目标设置它的一些 b运行ch 名称(强制推送)。

因为推送的目标是设置它的 b运行ch 名称,几个特殊条件成立:

  1. b运行ch 不得检出到工作树中。如果存储库是使用 --bare 创建的,则此方法效果很好,因为它从未将任何 b运行ch 检出到工作树中。
  2. 或者,b运行ch 可以被签出到工作树中,但是接收推送的 Git 必须被告知允许这样的推送操作(并且其他条件必须满足).参见,例如, [Edit: or your better link, What is this Git warning message when pushing changes to a remote repository?.

由于这些原因,有时使用全取工作流程会更好;但是随后您必须使用第二个 Git 命令将新提交 合并 到本地存储库中。许多人喜欢为此使用 git pull 命令,因为它实际上首先 运行s git fetch,然后 运行s 第二个 Git 命令合并获取的提交.