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

时间:2018-09-12 19:23:50

标签: git git-merge git-fork

我们在组织中使用了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)

上游有两个分支机构

  1. 主控

  2. 开发

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

这是我尝试过的

git fetch upstream
git merge upstream/defect-875

defect-875是我的本地分支。

我总是收到此错误消息

  

合并:上游/缺陷875-我们无法合并

我也尝试过

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

如何解决此问题?

2 个答案:

答案 0 :(得分:1)

我认为您应该说git merge upstream/devel -m "Merging from devel"(已检查出fault-875,以便我们在同一页面上。)

答案 1 :(得分:0)

我认为

eftshift0's answer是正确的选择,但听起来您应该学习一些Git技巧。

关于Git的第一件事是,它主要与 commits 有关。分支-或实际上是分支名称(请参阅What exactly do we mean by "branch"?)-存在于Git中,以便Git和我们都能找到提交。

您可能已经知道提交实际上是源树的快照。 (如果您不这样做,那么现在就可以了!)但是它还有更多点。首先,每个提交都以其哈希ID的形式具有唯一的“真实名称”。分支名称是表达某些提交的真实名称的一种方式(哈希ID),git rev-parse将为您显示实际的哈希ID:

$ git rev-parse master
c05048d43925ab8edcb36663752c2b4541911231

这些大的丑陋ID似乎是随机的,但实际上完全由提交本身的内容确定。这些内容非常简短-这是上面的提交,其中@<address>受到了一些限制,以减少垃圾邮件:

$ git cat-file -p c05048d43925ab8edcb36663752c2b4541911231 | sed 's/@/ /'
tree a446a29ef7ca90d9c64825fb00a0f1e1a099ca18
parent e9983f8965c0875cc6727e9644c84ff1dfc99372
author Junio C Hamano <gitster pobox.com> 1536096807 -0700
committer Junio C Hamano <gitster pobox.com> 1536096807 -0700

Git 2.19-rc2

Signed-off-by: Junio C Hamano <gitster pobox.com>

上面的 tree 行是提交如何保存源快照的方式(通过使用另一个Git内部对象)。 author committer 行告诉我们谁进行了提交,以及何时— 1536096807表示Tue Sep 4 14:33:27 2018 parent 行给出了在该提交之前 的提交的丑陋哈希ID。

我们说其中每个具有哈希ID的事物都指向对象。有关更多信息,请参见Think Like (a) Git,但对于此答案,让我将其绘制如下:

...  <-c05048d43925ab8edcb36663752c2b4541911231   <--master

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

所有这些名称和对象都位于您自己的存储库中

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

但是您确实从其他一些Git中得到了一些 提交。您可以使用Internet通过让Git调用那些Git来实现。他们的Git存储库中有 their 提交以及 their 分支名称。所有提交都具有唯一的哈希ID,但是如果提交具有与 you 的某些提交具有相同的真实名称的相同哈希ID,则它们和根据定义,您具有相同的提交

git fetch获得您没有的提交

他们的分支名称不必匹配,但是提交哈希ID do 必须匹配。它们匹配,或者您有提交,或者它们有您没有的提交。因此,您的Git调用他们的Git并说:您拥有什么名称,它们的提交哈希ID是什么?他们的Git为您的Git提供了此列表,而您的Git自言自语:啊,我有这个 hm,我没有那个。然后,您的Git会向他们的Git列出他们拥有的提交列表,您的Git 想要,然后他们的Git将这些提交(包括快照)打包并发送过来。

在此过程结束时,您拥有所有提交(包括您已经拥有的所有提交) plus 所有提交。请注意,它们不仅向您发送最尖端的提交(分支名称直接指向它们),而且还向您发送父提交,父父提交等等,以便您获得 connect back的提交您自己的提交。

git fetch也获得了它们的分支名称;现在呢?

您也有他们的分支名称。但是这些是他们的分支名称,所以现在您的Git 重命名这些东西。如果您的Git使用git fetch upstream调用了他们的Git,则您的Git 重命名他们的master,将其命名为upstream/master,并重命名其devel,将其命名为upstream/devel

我们可以这样绘制提交,使用回合o代表实际的哈希ID,尽管我现在必须开始猜测很多提交它们的方式没错在运行git fetch upstream之前,您需要执行以下操作:

... <-o <-o <-o   <-- master
               \
                o   <-- defect-875

您的defect-875提交指向您的master分支的尖端,该分支指向更早的提交,依此类推。不过,一旦运行git fetch upstream,您将获得更多类似的内容:

                     o--o   <-- upstream/devel
                    /
             o--o--o   <-- upstream/master
            /
...--o--o--o   <-- master
            \
             o   <-- defect-875

(绘制箭头太难了,所以我已经用线代替了其中的大部分,只记得它们总是指向后)。

现在您可以合并

运行git merge时,必须告诉Git 要与之合并的提交。通常,您可以给它指定一个分支名称,或使用upstream/devel之类的远程跟踪名称。该名称解析为提交哈希ID,就像我在上面显示的那样,您可以运行git rev-parse来查看其工作原理。 因为 git fetch获得了他们的devel并将其重命名为您自己的upstream/devel,所以它可以正常工作。如果尚未运行git fetch upstream,则必须首先执行该操作,以便您的Git拥有提交并已将其devel重命名为upstream/devel

合并

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

                     o--R   <-- upstream/devel
                    /
             o--o--o
            /
...--o--o--B
            \
             L   <-- defect-875 (HEAD)

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

然后,您的Git实际上将运行两个git diff命令,以查看您所做的更改-BL的不同之处,并查看它们的更改,即, BR有什么区别:

git diff --find-renames <hash-of-B> <hash-of-L>   # what we did
git diff --find-renames <hash-of-B> <hash-of-R>   # what they did
现在,

Git结合了合并-这两组更改。如果它们容易组合,则Git会将组合的更改应用于与提交B关联的快照,并从结果中进行新的提交。这是合并提交,一种特殊的提交。使其与众不同的原因仅仅是,它有两个父母而不是一个父母:它首先列出自己的提交L作为其第一父提交,然后列出他们的提交R作为其第二父提交。

如果我们将图形上下颠倒,可能会有所帮助,所以我将在此处进行。结果看起来像这样:

             L----------------M   <-- defect-875 (HEAD)
            /                /
...--o--o--B                /
            \              /
             o--o--o      /
                    \    /
                     o--R   <-- upstream/devel

此新提交M位于您自己的defect-875分支上。

将新提交发送到upstream

现在,如果您仍然获得授权,则可以使用git push在您的Git引用为defect-875的Git存储库上创建一个upstream分支,使用:

git push upstream defect-875

这让您的Git调用他们的Git,向他们 提供拥有他们他们没有的提交列表-在这种情况下,恰好是两个提交LM,然后向他们的Git建议他们使用提交defect-875作为提示提交,创建一个名为M的分支。

如果他们服从所有这些请求和建议,您的Git会记住他们是这样做的,并将名称upstream/defect-875添加到您自己的名称集中:

             L----------------M   <-- defect-875 (HEAD), upstream/defect-875
            /                /
...--o--o--B                /
            \              /
             o--o--o      /
                    \    /
                     o--R   <-- upstream/devel

您自己的分支defect-875不会发生任何变化:您的名字defect-875仍会标识您的提交M(通过其实际的哈希ID,无论如何)。您只给了他们的Git这两个提交,并让他们的Git设置了他们的名称defect-875即可与您的匹配。

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

git branch --set-upstream-to=upstream/defect-875 defect-875

如果您想在运行git push时同时执行这两项操作,则可以通过在-u上添加git push标志来一次完成所有操作:

git push -u upstream defect-875

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