git分支和master上的冲突了

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了git分支和master上的冲突了相关的知识,希望对你有一定的参考价值。

我在git上新建了一个分支master_11,修改了代码,提交了我本地分支的代码。这个时候临时有一个需求需要在master上处理,我从master_11切换到了master上,在master修改了代码提交到服务器之后,回到master_11上,为什么更新下来会有master上刚才我更新的代码呢?

按照逻辑应该没有呀,请大神解释

参考技术A git支持很多种工作流程,我们采用的一般是这样,远程创建一个主分支,本地每人创建功能分支,日常工作流程如下:
去自己的工作分支
$ git checkout work
工作
....
提交工作分支的修改
$ git commit -a
回到主分支
$ git checkout master
获取远程最新的修改,此时不会产生冲突
$ git pull
回到工作分支
$ git checkout work
用rebase合并主干的修改,如果有冲突在此时解决
$ git rebase master
回到主分支
$ git checkout master
合并工作分支的修改,此时不会产生冲突。
$ git merge work
提交到远程主干
$ git push
这样做的好处是,远程主干上的历史永远是线性的。每个人在本地分支解决冲突,不会在主干上产生冲突。
t欧姆定律:I?UR电功公式: W = U I tW = U I t

究竟是什么导致了git中的合并冲突?

1)有一个'master'分支,其中包含一个文件

1

2

3

4

5

2)A从'master'获取分支并编辑

1

2

100

3

4

5

3)B从'master'获取分支并编辑

1

2

3

4

200

5

4)现在推动变成主人。然后B试图推动。

B会发生什么?任何合并冲突或没有合并冲突?原因是什么?

答案

最简单的答案是:如果两个开发人员在同一个文件(和同一个分支)中更改了相同的代码行,git将假定存在冲突。

无论是谁先提出并推动,都是“胜利者”。第二个必须处理冲突。他不能推动,直到他从原点撤下所有变化并解决冲突。

另一答案

你的问题意味着事情并非如此。

具体来说,git push只推动现有的提交。它没有合并任何东西,事实上,它甚至从未试图合并任何东西。

在您的问题中,涉及三个实体(人员和存储库)。 A人(让我们称她为Alice),B人(让他们称他为Bob)和C人(让他们称他为Central-Server,他实际上只是一台机器,而不是一个人,虽然这并不重要)。

Alice和Bob都是从Central-Server获取某个存储库的副本(克隆)开始的。它们得到完全相同的克隆(这就是为什么它们被称为“克隆”):Alice的克隆匹配Bob的克隆匹配Central-Server上的克隆。他们通过运行git clone <url>来执行此操作,其中<url>指向中央服务器(github或其他任何东西),并且他们的git将名称origin保存下来(我们很快会再次看到此名称)。

让我们绘制一下所有三个实体现在拥有的git提交图(的一部分):

... - C7 - C8   <-- master

现在爱丽丝和鲍勃都做出了改变,但他们做了不同的改变。爱丽丝承诺改变:

... - C7 - C8 - A   <-- master

然后Alice运行git push origin将她的工作推回到Central-Server。 Central-Server查看了她的请求,其中说“在A将链接C8添加到链的末尾,并使master指向A”。此操作会向链中添加新提交,因此允许,因此Central-Server向Alice回复“OK”,并且她已全部完成。 Central-Server的存储库现在看起来和Alice的相同,因为它们都在旧提交A之后有新的提交C8master指向提交A(并且提交A指向旧的C8)。

同时Bob已做出改变并添加了一个新的提交,他的提交图现在看起来像这样:

... - C7 - C8 - B   <-- master

Bob不知道Alice已经提交了A,也没有成功将它推送到Central-Server。他去了git push origin,但这次Central-Server得到一个请求,说“在C8链接的末尾添加提交B,然后让master指向B”。如果Central-Server这样做,效果将是:

                A
              /
... - C7 - C8 - B   <-- master

也就是说,提交A将保持浮动,没有任何指向它。 (分支master将指向BB将指向C8,没有任何指向A。)这通常是一种糟糕的状态,git拒绝它,所以Central-Server告诉Bob:

rejected (non-fast-forward)

请注意,没有合并,也没有变基。

现在鲍勃的工作是进行合并(或改组)。他应该这样做:

  1. 从拥有它的人那里获取更新。谁拥有它?爱丽丝拥有它,但Central-Server也是如此。他刚刚要求推送到Central-Server,后者告诉Bob“不”,所以他不妨从Central-Server获取它。
  2. 合并(或rebase),解决任何冲突。
  3. 重试推送。

如果Bob选择“合并”并做适当的合并工作,这是他的新提交图:

... - C7 - C8 - A - M   <-- master
                 /
                B

请注意新的合并提交M。现在Bob可以重新尝试推送到Central-Server,后者目前拥有以A结尾的链。这次中央服务器将看到使master指向M的请求,并且由于M指向A,该请求将被允许(现在它是“快进”)。

当然,如果Alice(或Dave或Emily或Frank)通过在A之后添加新提交并将其发送回Central-Server而击败Bob,那么Bob将不得不再次合并(或重新绑定),然后再试一次。

How does Bob manage all this?

这是Bob的选择是合并还是变基。无论哪种方式,Bob都必须解决任何合并冲突 - 无论他使用哪种方法,他都会得到相同的合并冲突。并且,在任何一种情况下,他应该开始运行:

git fetch origin

(或只是git fetch,它将自动使用origin)。

让我们看一下在变基或合并之前Bob的提交图:

                A   <-- origin/master
              /
... - C7 - C8
              
                B   <-- master

请注意,Bob的master指向提交B,Bob有另外一件事 - 这个origin/master指向Alice的提交A。这就是git fetch所做的:它从Central-Server中带来最新版本(或者如果Bob直接从Alice获取,将其从她身上带过来,因为她有相同的提交),然后使一些标签指向该提交。标签以origin/...开头,因为这是我们允许git clone使用的名称:它只是将origin/粘贴在另一个名称前面(在这种情况下为master),以便我们可以区分它们。

如果鲍勃选择改变而不是合并,他将把他的git复制他的提交B到新的提交B'

                A       <-- origin/master
              /   
... - C7 - C8       B'  <-- master
              
                B

鲍勃的原始B会发生什么?答案是:它被废弃了。它保留在存储库中一段时间​​(默认30天),以防Bob需要它,保存在Bob的reflog中,但除非你(或Bob)明确要求git查看,否则你看不到这些提交,所以它们似乎消失了。

如果Bob选择合并,他会得到:

                A       <-- origin/master
              /   
... - C7 - C8       M   <-- master
                 /
                B

这是我们在上面绘制的图,我们刚刚提升了A节点,以便我们可以指向它的箭头(标记为origin/master)。

在任何一种情况下,Bob现在可以尝试推送,因为他的新提交 - B'M-points返回提交A,因此他只要求Central-Server添加新提交而不是忘记或放弃提交A

What about the merge itself?

Git将尝试通过比较Alice所做的更改(添加100的一行)与Bob所做的更改(添加一行200)来帮助Bob。如果git决定这些更改不会相互冲突,它将保留这两个更改。如果它确定这两个更改会影响文件的同一部分,则会给Bob一个合并冲突,标记文件的更改区域,并让Bob决定如何组合它们。

Bob可以使用他喜欢的任何东西来实现组合结果。 Bob应该确保结果是正确的,然后Bob应该告诉他的git到git add文件的最终版本和git commit来提交更改。如果他用来组合这些更改的命令是git merge,这个将进行合并提交。如果它是git rebase,这将使新的副本B'


1如果鲍勃选择git rebase,他可以使用git rebase --continue,它将为他做出承诺。虽然鲍勃首先做git commit然后做git rebase --continue是安全的(并且在git 1.5左右的时候,在继续变换之前,必须手动执行提交部分)。

A final note about git pull

我鼓励新的git用户从git fetch开始,然后做自己的git mergegit rebase。许多文件告诉你从git pull开始,但我认为这是一个错误。 git pull命令是一个方便:它运行git fetch,然后运行git mergegit rebase,但这有几个缺陷。没有一个是非常严重的,但这些对新用户不利:

  1. 在您甚至可以查看更改之前,它会选择合并与rebase。
  2. 默认是合并,这通常是新用户的错误答案,他们通常可能应该进行rebase。您可以更改默认值,但新用户不知道提前执行此操作。你可以添加--rebase告诉它改变,但你可以忘记包含这个标志。
  3. 它所做的合并是一个"foxtrot merge":它让父母提交错误的方向。
  4. 与手动合并相比,这些论点令人困惑:git pull origin <branch> vs git merge origin/<branch>。 (当然,如果你想避免foxtrot合并,你也不能使用后者,但你可能应该重新定位。)
  5. 如果你提供了太多的参数(git pull origin master develop),它会使章鱼合并,这不是新用户应该考虑的事情。 :-)
  6. 它曾经有许多破坏工作的bug案例。我相信它们都是固定的,但使用git fetch后跟一个单独的git mergegit rebase一直避免这些错误。
  7. 最后,这里发生了太多的魔法。它应该是方便的(对于那些使用git的老手,它很方便)但它只是模糊不清。
另一答案

当B尝试推送时,会有错误返回,因为A已被推送更改为master。那你应该这样做,

git fetch
git rebase origin/master

在执行rebase步骤时,不会发生冲突,因为A更改了文件的第3行,B更改了文件的第5行。那你可以做到,

git commit -m ""
git push
另一答案

当git不知道如何处理代码的相同部分中的两个更改(未按顺序进行)时,会发生合并冲突。在您的情况下,已更改的行是不同的,因此git将能够合并提交而不会发生冲突。但是,一旦A中的提交被推送,B中的提交就不能在没有在A之上重新定位的情况下被推送。

在这种情况下你不能推B:

----M-----A
     ----B

如果你去B并输入并使用:

git rebase A

您的代码在本地存储库中将如下所示:

----M-----A-----B

你也可以推送提交B.

以上是关于git分支和master上的冲突了的主要内容,如果未能解决你的问题,请参考以下文章

git 怎样将分支上的一个单文件合并到主分支上(master)

git合并分支

GitGit 分支管理 ( 解决分支合并冲突 | 本地处理文件冲突 )

GitGit 分支管理 ( 解决分支合并冲突 | 本地处理文件冲突 )

git---怎样将分支上的一个单文件合并到主分支上(master)

git分支管理