从上游远程分支合并到本地远程分支

Kar*_*tik 1 git git-merge git-fork

我们在组织中使用分叉模型,我正在尝试将更新从上游分支合并到本地分支。

这是我的 git 设置。

kartik@ ~/sourcecode/myproject (defect-875) $ git remote -v
origin  git@github.com/kartik/myproject.git (fetch)
origin  git@github.com/kartik/myproject.git (push)
upstream    git@github.com:MyOrg/myproject.git (fetch)
upstream    git@github.com:MyOrg/myproject.git (push)
Run Code Online (Sandbox Code Playgroud)

上游有两个分支

  1. 掌握

  2. 开发

我需要将本地分支与devel上游分支同步。

这是我尝试过的

git fetch upstream
git merge upstream/defect-875
Run Code Online (Sandbox Code Playgroud)

其中,defect-875 是我的本地分支。

我总是收到此错误消息

合并:upstream/defect-875 - 我们不能合并

我也尝试过这个

kartik@ ~/sourcecode/myproject (defect-875) $ git merge upstream/devel -m "Merging from seo redirect."
 merge: upstream/devel - not something we can merge
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

tor*_*rek 7

我认为eftshift0 的答案是正确的,但听起来你应该学习一些 Git 技巧。

\n\n

关于 Git 首先要了解的是它主要与提交有关。分支 \xe2\x80\x94 或者实际上是分支名称(请参阅“分支”到底是什么意思?)\xe2\x80\x94 存在于 Git 中,以便 Git 和我们可以找到提交。

\n\n

您可能已经知道提交实际上是源树的快照。(如果您没有,那么,现在您可以了!)但它还有更多功能。首先,每个提交都有一个以其哈希 ID 形式呈现的唯一“真实名称”。分支名称是表达某些提交的真实名称\xe2\x80\x94和哈希ID\xe2\x80\x94的一种方式,git rev-parse并将向您显示实际的哈希ID:

\n\n
$ git rev-parse master\nc05048d43925ab8edcb36663752c2b4541911231\n
Run Code Online (Sandbox Code Playgroud)\n\n

这些又大又丑的ID看起来是随机的,但实际上完全是由commit本身的内容决定的。这些内容非常短\xe2\x80\x94这是上面的提交,并@<address>进行了一些修改以减少垃圾邮件:

\n\n
$ git cat-file -p c05048d43925ab8edcb36663752c2b4541911231 | sed \'s/@/ /\'\ntree a446a29ef7ca90d9c64825fb00a0f1e1a099ca18\nparent e9983f8965c0875cc6727e9644c84ff1dfc99372\nauthor Junio C Hamano <gitster pobox.com> 1536096807 -0700\ncommitter Junio C Hamano <gitster pobox.com> 1536096807 -0700\n\nGit 2.19-rc2\n\nSigned-off-by: Junio C Hamano <gitster pobox.com>\n
Run Code Online (Sandbox Code Playgroud)\n\n

上面的树线是提交如何保存源快照(通过使用另一个 Git 内部对象)作者和提交者行告诉我们谁进行了提交以及何时\xe2\x80\x941536096807表示。父行给出了此提交之前的提交的又大又难看的哈希 ID 。Tue Sep 4 14:33:27 2018

\n\n

我们说每个有哈希 ID 的东西都指向该对象。有关此内容的更多信息,请参阅Think Like (a) Git,但对于这个答案,让我这样画出来:

\n\n
...  <-c05048d43925ab8edcb36663752c2b4541911231   <--master\n
Run Code Online (Sandbox Code Playgroud)\n\n

名称 master 指向此提交,该提交又指向较早的提交e9983f8965c0875cc6727e9644c84ff1dfc99372。较早的提交指向更早的提交,依此类推。

\n\n

所有这些名称和对象都是您自己的存储库的本地名称和对象

\n\n

您在自己的存储库中拥有所有这些分支名称,例如master和。defect-875它们不依赖于您自己的 Git 之外的任何内容。它们也指向您本地的提交,并且这些提交\xe2\x80\x94包括它们的快照及其父提交和这些提交的快照,一直追溯到历史记录\xe2\x80\x94不依赖于任何东西也可以在您自己的 Git 之外。

\n\n

但您确实从其他一些 Git获得了一些提交。您可以通过让 Git 使用 Internet 调用这些 Git 来完成此操作。他们的 Git 存储库包含带有分支名称的提交。这些提交都具有唯一的哈希 ID,但如果它们的提交具有相同的哈希 ID\xe2\x80\x94 相同的真实名称\xe2\x80\x94 与拥有的某些提交相同,那么根据定义,它们和您具有相同的哈希 ID犯罪

\n\n

git fetch获得他们拥有而你没有的提交

\n\n

它们的分支名称不必匹配,但提交哈希 ID必须匹配。要么他们匹配,并且您有提交,要么他们有您没有的提交。所以你的 Git 调用他们的 Git 并说:你有什么名字,他们的提交哈希 ID 是什么? 他们的 Git 给你的 Git 这个列表,你的 Git 对自己说:啊,我有这个,或者嗯,我没有那个。 然后,你的 Git 向他们的 Git 提供他们拥有的、你的 Git想要的提交列表,然后他们的 Git 打包这些提交\xe2\x80\x94,包括他们的快照\xe2\x80\x94,并将它们发送出去。

\n\n

在此过程结束时,您将拥有您的所有提交(包括您已经拥有的他们拥有的任何提交)以及他们的所有提交。请注意,它们不仅会向您发送最顶端的提交\xe2\x80\x94(分支名称直接指向的提交\xe2\x80\x94),还会根据需要发送父提交、父提交的父提交等这样你就可以得到连接回你自己的提交的提交。

\n\n

git fetch还获得他们的分支名称;怎么办?

\n\n

您还有他们的分支机构名称。但这些是它们的分支名称,所以现在你的 Git会重命名这些东西。如果你的 Git 调用了他们的 Git git fetch upstream,你的 Git会重命名他们的master,调用它upstream/master,并重命名他们的devel,调用它upstream/devel

\n\n

我们可以像这样绘制提交,使用 roundo代表实际的哈希 ID,尽管我现在必须开始猜测他们有多少次提交而你没有。在你运行之前git fetch upstream,你会得到这样的东西:

\n\n
... <-o <-o <-o   <-- master\n               \\\n                o   <-- defect-875\n
Run Code Online (Sandbox Code Playgroud)\n\n

您的defect-875提交指向master分支的尖端,分支的尖端又指向某个较早的提交,依此类推。然而,一旦你运行git fetch upstream,你会得到更多类似这样的东西:

\n\n
                     o--o   <-- upstream/devel\n                    /\n             o--o--o   <-- upstream/master\n            /\n...--o--o--o   <-- master\n            \\\n             o   <-- defect-875\n
Run Code Online (Sandbox Code Playgroud)\n\n

(绘制箭头变得太难了,所以我用线替换了大部分箭头\xe2\x80\x94,只要记住它们总是向后指向)。

\n\n

现在您可以合并

\n\n

当您运行时git merge,您必须告诉 Git要合并哪个提交。您通常通过为其指定分支名称或远程跟踪名称(例如upstream/devel. 该名称解析为提交哈希 ID\xe2\x80\x94,您可以运行git rev-parse查看其工作原理,正如我上面所示。它之所以有效,是因为 git fetch获得了他们的devel并将其重命名为您自己的upstream/devel。如果您还没有运行git fetch upstream,您必须先执行此操作,以便您的 Git 拥有它们的提交,并将它们重命名devel为您的upstream/devel.

\n\n

合并

\n\n

此时,所有工作都在您自己的存储库中进行。 假设我的绘图是准确的;但让我们将其简化为有趣的名称,并将该单词附加HEAD到您现在签出的名称上。我还将为三个有趣的提交输入一个字母的名称:

\n\n
                     o--R   <-- upstream/devel\n                    /\n             o--o--o\n            /\n...--o--o--B\n            \\\n             L   <-- defect-875 (HEAD)\n
Run Code Online (Sandbox Code Playgroud)\n\n

运行git merge upstream/devel将找到您当前的或HEAD提交的L(对于 Left 或 Local 或--ours);您的提交标记为upstream/devel,即提交R(对于 Right 或 Remote 或--theirs);并使用LR回到共同的起点,即提交B(对于 Base)。

\n\n

然后,您的 Git 实际上将运行两个命令,以查看您更改了 \xe2\x80\x94 与vs \xe2\x80\x94git diff中的不同之处,并查看它们更改了哪些内容,即vs中的不同之处:BLBR

\n\n
git diff --find-renames <hash-of-B> <hash-of-L>   # what we did\ngit diff --find-renames <hash-of-B> <hash-of-R>   # what they did\n
Run Code Online (Sandbox Code Playgroud)\n\n

Git 现在将\xe2\x80\x94 合并\ xe2\x80\x94 这两组更改。如果它们可以轻松组合,Git 会将组合的更改应用于与 commit 关联的快照B,并根据结果进行新的提交。这是合并提交,一种特殊的提交。它的特别之处在于它有两个父项而不是一个:它L首先列出您自己的提交作为其第一个父项,然后列出他们的提交R作为其第二个父项。

\n\n

如果我们把图颠倒过来可能会有一点帮助,所以我会在这里这样做。结果如下:

\n\n
             L----------------M   <-- defect-875 (HEAD)\n            /                /\n...--o--o--B                /\n            \\              /\n             o--o--o      /\n                    \\    /\n                     o--R   <-- upstream/devel\n
Run Code Online (Sandbox Code Playgroud)\n\n

这个新提交M存在于您自己的defect-875分支上。

\n\n

将新提交发送至upstream

\n\n

现在,如果您已获得授权,您现在可以使用以下命令在 Git 引用的 Git 存储库上git push创建分支:defect-875upstream

\n\n
git push upstream defect-875\n
Run Code Online (Sandbox Code Playgroud)\n\n

这让你的 Git 调用他们的 Git,向他们提供拥有但他们没有的提交列表,在本例中正是两个提交LM\xe2\x80\x94,然后向他们建议Git 他们defect-875使用 commit创建了一个名为 的分支M作为其提示提交。

\n\n

如果他们遵守所有这些请求和建议,您的 Git 将记住他们这样做了,并将名称添加到您自己的一组名称中upstream/defect-875

\n\n
             L----------------M   <-- defect-875 (HEAD), upstream/defect-875\n            /                /\n...--o--o--B                /\n            \\              /\n             o--o--o      /\n                    \\    /\n                     o--R   <-- upstream/devel\n
Run Code Online (Sandbox Code Playgroud)\n\n

您自己的分支defect-875不会以任何方式更改:您的名称defect-875仍然标识您的提交M(通过其实际的哈希 ID,无论是什么)。您只需向他们的 Git 提供这两个提交,并让他们的 Git 将名称设置defect-875为与您的名称相匹配。

\n\n

如果您愿意,现在可以将您自己的分支的上游defect-875设置为名称upstream/defect-875

\n\n
git branch --set-upstream-to=upstream/defect-875 defect-875\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您想在运行时同时执行这两项操作git push,则可以通过将标志添加-u到您的git push

\n\n
git push -u upstream defect-875\n
Run Code Online (Sandbox Code Playgroud)\n\n

但这只是一种方便的优化。

\n