Lim*_*man 5 git synchronization repository
我面临以下问题并且没有想法:
我的公司不允许我们的开发人员直接访问互联网。因此,我们迫切需要自己的 git 存储库。到目前为止还算正常。我们的开发人员正在开发的项目得到了一家也为我们开发的外部公司的支持。该公司有自己的 git 存储库。他们无法直接访问我们的 git 存储库,我们也无法直接访问他们的 git 存储库。仅通过能够访问其存储库的僻静服务器提供访问权限。
为了更好地理解:
我的公司回购 = A ,外部公司回购 = B
这两个存储库都需要保持同步。两者具有相同的分支,A 中所做的更改应转移到 B,反之亦然。两家公司同时在所有分支机构开展业务。我告诉他们保留分离的分支来工作,但他们不听。反正...
到目前为止,我的解决方案是我在这里找到的这段脚本:
$ORIGIN_URL=EXTERNAL REPO B
$REPO1_URL=INTERNAL REPO A
/usr/bin/git clone -c http.sslVerify=false --bare $ORIGIN_URL
/usr/bin/git remote add --mirror=fetch repo1 $REPO1_URL
/usr/bin/git -c http.sslVerify=false fetch --all
/usr/bin/git fetch repo1 --tags
/usr/bin/git push origin --all
/usr/bin/git push origin --tags
/usr/bin/git push repo1 --all
/usr/bin/git push repo1 --tags
Run Code Online (Sandbox Code Playgroud)
问题是,由于两家公司在相同的分支上工作(即 A/fix1 和 B/fix1),我经常遇到冲突(更新被拒绝,因为推送的分支提示位于其远程(非快进)后面)。
我正在尝试找到一些脚本,可以为我和两家公司解决这个问题。
我什至很感激您就如何解决我一次又一次面临的这一冲突提供一些建议。
感谢您的帮助
问候 L。
听起来您好像认为他们的分支与您的分支具有相同的名称,那么它们就是“同一分支”。这不一定是真的。看待它的一种方法是,git永远不要将两个存储库中的分支视为“同一分支”;它只是有关于如何集成存储库之间的更改的规则。根据您配置这些规则的方式,您可能会将它们视为“同一分支”。
因此,首先要以不同的方式配置规则。实际上 git 的默认行为在这里并不算太糟糕;但遥控器--mirror=fetch上的设置repo1会以可能没有帮助的方式覆盖默认值。如果我们不这样做的话,事情会简单一些。我们还可以通过手动添加两个遥控器而不是克隆其中一个存储库来让事情变得更简单。(这不是必要的;我只是认为这会让正在发生的事情变得更清楚一些。)
git init --bare
git remote add external $ORIGIN_URL
git remtoe add internal $REPO1_URL
git fetch --all
Run Code Online (Sandbox Code Playgroud)
现在假设每个仓库都有 abranch1和 a branch2,并且两者都不同,你的新仓库看起来像
E <--(remotes/external/branch2)
/
o -- x -- D <--(remotes/internal/branch2)
\
x -- A -- B <--(remotes/internal/branch1)
\
C <--(remotes/external/branch1)
Run Code Online (Sandbox Code Playgroud)
从这里,您可以通过命名分支将外部分支共享到内部存储库,而无需担心分支名称冲突。
git push internal refs/remotes/external/*:refs/heads/external/*
Run Code Online (Sandbox Code Playgroud)
现在你的内部仓库看起来像
E <--(external/branch2)
/
o -- x -- D <--(branch2)
\
x -- A -- B <--(branch1)
\
C <--(external/branch1)
Run Code Online (Sandbox Code Playgroud)
当然,外部更改不会与内部更改集成,但这与它们根据您最初的建议使用不同的分支名称是一样的。这是预料之中的——在某些时候,有人必须将外部更改合并到内部分支中(反之亦然),此时必须解决冲突。
(当然,您可以使用某些实践来使合并冲突解决尽可能轻松 - 例如支持短期分支和频繁的增量集成。但您不能完全消除它们。)
您可以类似地以非集成形式与外部存储库共享内部更改;例如通过做类似的事情
git push external refs/remotes/internal/*:refs/heads/internal/*
Run Code Online (Sandbox Code Playgroud)
但这留下了一些关于谁整合变革以及如何整合变革的问题,特别是因为听起来外部公司在这方面没有按照他们的要求去做。因此,您可能希望在内部集成他们的更改,然后使用他们已经知道的分支名称共享集成的更改。
诀窍是,您必须使用“获取、集成、推送”模型来避免像您已经看到的那样的“非快进”错误。当您的工作克隆能够直接与远程通信时,通常会这样做
git pull
# resolve conflicts
git push
Run Code Online (Sandbox Code Playgroud)
因为您必须使用此桥存储库,但可能不想在该存储库中完成所有集成工作,所以您需要执行额外的步骤。这可能会很烦人,因为完成获取/集成/推送周期所需的时间越长,在获取之后但推送之前出现新更改的机会就越大,从而要求您执行另一个获取/集成/推送周期。当然,推送是在逐个引用的基础上接受或拒绝的,所以随着时间的推移,它应该会成功(因为尝试 1 成功推送分支 A,尝试 2 成功推送分支 B 和 C,等等)。
因此,集成工作流程可能如下所示:
在桥存储库上
fetch --all
git push external refs/origins/internal/*:refs/heads/*
Run Code Online (Sandbox Code Playgroud)
这尝试直接更新他们的分支。有些裁判可能会被拒绝;没关系,您希望在下一个周期中得到它们。
git push internal refs/origins/external/*:refs/heads/external/*
Run Code Online (Sandbox Code Playgroud)
这应该总是成功的。为了确保它始终成功,您应该确保永远不要对分支进行内部提交external/*。出于这个原因,您可能想要使用非分支引用(即将外部引用保留在refs/heads层次结构之外),但并不完全清楚您将它们放在哪里。你可以继续像远程跟踪裁判一样对待他们
git push internal refs/origins/external/*:refs/origins/external/*
Run Code Online (Sandbox Code Playgroud)
这有点可疑,因为内部存储库实际上没有一个名为external...
无论如何,您的开发人员现在可以通过某种方式看到更改并将它们集成到分支的本地版本中,从而解决冲突。然后在下一个集成周期中,您fetch将获得合并提交,您可以尝试将其推送到远程。根据需要重复。
当然,这是基于在协调内部和外部变革方面“他们似乎没有按照要求做的事情”。让每个人在同一页面上使用存储库的次数越多,您遇到的麻烦就越少。(就像在本例中一样,必须在内部进行所有集成,并且可能会延迟对内部更改的外部可见性。)
从这个意义上说,我喜欢将内部引用推送到外部存储库并将外部引用推送到内部存储库的想法,以便两家公司的开发人员都可以看到两组更改。但你不希望外部开发人员提交到内部分支,反之亦然,因为这样集成就会开始变得奇怪,比如 rsfs/heads/internal/external/master 或同样愚蠢的分支。