现在,一般我用
git pull origin develop
为获得来自开发分支的最新更新。最近,我的团队一直过渡到使用衍合,而不是合并,所以我有点糊涂了一些东西。之前我的工作流程是非常简单的。我先签入开发分支和使用
git checkout -b feature/foo
然后我会让我的变化,提交,然后把他们。通常情况下,开发分支将就此做了一些改变,我会用
git pull origin develop
以获得最新的变化,并有冲突只有当其他人修改了同一个文件。然而,当我使用
git pull origin develop --rebase
我注意到,我会冲突与我自己的分支机构,即使我谁已经修改它的唯一的人。对此有一个特别的原因?有没有办法避免这些合并冲突,我有我自己的分支?
首先,让我们注意,git pull
主要包括运行两个Git的命令。这意味着它的意思是一个方便的操作,让你git pull
entergit fetch
而不是键入git .....
。第一个命令总是git fetch
,第二个是你的选择:它默认为git merge
,但你可以选择git rebase
。它需要几乎同样多的打字做一个命令为两个,当你想变基,所以它不是真的毕竟很方便,我建议使用单独的git fetch
和第二个命令,至少要等到你很熟悉Git.1
所以,你的问题真的解决了一个简单的办法:为什么有时重订有合并没有冲突?而且还有一个问题的答案,这实际上是相当简单:再次基于主要只是反复摘樱桃,樱桃采摘是合并的一种形式。所以,当你合并,你有一个地方,你可以得到的冲突。如果你变基10名提交,你有十个地方,你可以得到的冲突。冲突本身可以是不同的为好,但机遇的规模是这里的主要因素。
1IN库与子模块,git pull
可以递归到子模块,在这种情况下,它两个以上的命令和它的便利方面变得显著。您还可以配置git pull
默认运行git rebase
,使得方便重新出现,即使没有子模块。我还是鼓励新用户使用两个独立的命令,不过,对于该语法git pull
是有点怪异,几乎所有其他的Git的东西有点不同,它太容易混淆得到。有一个分配给拉了太多神奇的时候,居然所有的法术是从第二个命令,你需要学习合并理解变基。
虽然实现全棘手的小波折,合并背后的想法很简单。当我们问Git的合并,我们有“我们的工作”和“工作”。 Git的需要找出我们改变了他们改变什么,并结合这些变化。
为了做到这一点,Git的需要找到一个共同的起点。一个提交不是一套的变化都:它实际上是一个快照。 Git的可以显示这些快照从它的前任不同,即之一,同时抽取快照,看看有什么不同。因此,如果我们从一些开始犯了一些哈希ID B
,他们也从同一开始承诺:
C--D <-- our-branch (HEAD)
/
...--A--B
\
E--F <-- their-branch
随后的Git可以在B
快照比较我们最新的,D
,以及他们最新的,F
。无论是在B
-VS-D
不同的东西,我们改变了。无论是在B
-VS-F
不同的东西,他们改变了。 Git的则结合了变化,应用组合变化,从合并基础B
快照,并提交结果,不是一个而是两个前辈挂钩起来:
C--D
/ \
...--A--B G <-- our-branch (HEAD)
\ /
E--F <-- their-branch
为了达到这个目标,Git有运行:
git diff --find-renames hash-of-B hash-of-D
(我们改变)git diff --find-renames hash-of-B hash-of-F
(他们改变什么)当Git的去这两个差异列表结合起来,可以有地方,我们和他们改变了同一个文件的同一行。如果我们没有对这些线路进行相同的更改,Git会声明冲突并停止合并在中间,不作承诺G
着呢,迫使我们收拾残局,并完成合并创建G
。
背后摘樱桃的想法是复制一个承诺。要复制一个承诺,我们可以让Git把它变成一组更改:
git diff --find-renames hash-of-parent hash-of-commit
然后,我们可以采取这些变化,并用手涂抹别的地方他们,即其他一些承诺。举例来说,如果我们有:
C--D <-- our-branch (HEAD)
/
...--A--B
\
E--F <-- their-branch
我们喜欢他们在F
做,但不想E
本身呢,我们可以diff的E
VS F
,看看他们做了什么。我们可以用它来尝试使我们在D
快照相同的变化。然后,我们让自己一个新的承诺,让我们称之为F'
意味着F
的副本:
C--D--F' <-- our-branch (HEAD)
/
...--A--B
\
E--F <-- their-branch
但是,如果我们在C
取得显著的改变,或他们在E
取得显著的改变,可能很难让他们从E
到F
所做的更改与什么在我们D
快照排队。对于Git的来帮助我们,并自动执行此复制,Git会想知道:什么是E
和D
之间有什么不同?也就是说,Git会想要运行:
git diff --find-renames hash-of-E hash-of-D
(他们在C
改变)别急,我们刚才看到上面同样的模式,E
中!而事实上,这恰恰是混帐在这里所做的:它使用相同的代码git diff --find-renames hash-of-E hash-of-F
,它只是强制合并基础,这将是F
对于常规合并,是犯git merge
,母公司承诺git merge
,我们是樱桃-picking。现在的Git结合了变化且其变动,将组合组更改快照中基在B
,并就自己的最终E
提交,但这次作为一个经常犯。
新提交重新使用提交信息的提交F
本身也使新的承诺E
(其中有一些新的哈希ID,从F'
的不同)类似于F
很多:F'
可能显示了相同或非常相似的,DIFF列出各,当然同样的提交日志信息。
与F
,此合并过程,我喜欢称之为合并为一个动词,可能会出错。如果不出差错,Git的抱怨合并冲突,以合并未完成的停止,让你收拾残局和提交。当你提交,Git会知道你完成了一个F
和在这一点上提交信息给你的副本,使git show
。
做一个git merge
,Git的方法:
git cherry-pick
从目标;F'
复制每次提交这在list.2一旦所有的待复制的提交已被成功复制,移动的Git分支名称复制列表的末尾。
假设我们要实现一个类似的设置之前,虽然我将列出几个在这里提交:
git rebase target
我们运行Think Like (a) Git,这样的Git列出了提交复制:git cherry-pick
,按照这个顺序。然后,Git首先出来承诺 C--D--E--F <-- our-branch (HEAD)
/
...--A--B
\
G--H <-- their-branch
为“分离的头”:
git rebase their-branch
现在Git会摘樱桃C-D-E-F
复制。如果顺利的话:
H
Git的重复的 C--D--E--F <-- our-branch
/
...--A--B
\
G--H <-- their-branch, HEAD
,C
和 C--D--E--F <-- our-branch
/
...--A--B
\
G--H <-- their-branch
\
C' <-- HEAD
。一旦完成D
和E
我们在此状态下:
F
Git的完成复制D
到E
后,底垫的最后一步是将抽出的名字 C--D--E--F <-- our-branch
/
...--A--B
\
G--H <-- their-branch
\
C'-D'-E' <-- HEAD
到指向最终复制承诺,并重新连接F
它:
F'
每个摘樱桃做一个三路合并,与操作是母公司的合并基础提交被复制和“我们的”承诺是在脱离our-branch
音符,最初这是他们犯HEAD
之一,并作为我们进步,它变成了“他们的承诺 C--D--E--F [abandoned]
/
...--A--B
\
G--H <-- their-branch
\
C'-D'-E'-F' <-- our-branch (HEAD)
加上我们的工作”随着时间的推移。在“他们的”承诺是,每一次,我们自己的承诺。每个摘樱桃可以拥有所有常见的合并冲突,但在大多数情况下,多数人都没有。
有两种情况尤其是特别恶劣。其中的一个,可能是最常见的,就是任何时候你自己提交的,在列表中HEAD
举例来说,本身的东西,是在H
链樱桃选秀权(这往往不仅仅是两次提交,而更长的时间) - 或反之亦然,例如,可能H
本质上是C-D-E-F
。
如果你,或者他们,能够使该摘樱桃早轻松,没有冲突,你可能拷贝看起来几乎一模一样,甚至100%的完全一样,一个G-H
链。如果是这样的话,可以GIT中认识到,它是这样一个副本,从“被复制”列表中删除。在我们的例子中,如果H
是真的D'
,和Git可以看到,Git会从待复制列表中删除G-H
,只有复制H
。但如果不是,如果,例如,他们不得不改变D'
一堆自己的副本,使D
,Git会尝试复制C-E-F
而这些变化几乎肯定会与他们修改D
冲突。
如果合并,而不是复制,你会比较H
VS D
(他们)和H
VS B
(你的)和冲突的可能性也许减少。即使有冲突,他们可能更明显,更容易解决。如果冲突是因为一个不必要的副本,他们往往会根据我的经验,看棘手。
另一个常见的问题的情况是,在你的H
链,你最后几次提交了东西,你为了使合并更容易专门做了。也就是说,有人可能会说是这样的:我们改变foo的子系统,现在你需要第三个参数,你以后樱桃采摘B
的变化增加了第三个参数F
。复制C-D-E-F
和F
时,你会得到冲突。你可能会跳过复制E
,因为它是一个摘樱桃,然后复制C
不需要你固定在D
和E
冲突之后,但是这需要两个副本是需要修复,一个是自动删除,和一个你自己的,手动降。
因此,在最后,F
做一个合并,但D
做了很多的樱桃挑选,每一个都是-内部-合并,并且每一个都可以导致合并冲突。这并不奇怪,底垫得到更多的冲突!
2Technically,一个普通的(非交互式)E
经常不使用git merge
。相反,它使用了,实际上,git rebase
。使用git rebase
总是使用git cherry-pick
和git format-patch ... | git am ...
迫使非交互式git rebase -i
使用git cherry-pick
。即普通重订避免它事实上主要是刚刚从缓缴古(2008前期涨幅那么,可能)Git的,之前是教摘樱桃做一个适当的三方合并。
该git rebase -m
步骤使用git rebase
,因此,如果一个补丁失败,Git会“回落”到三路合并。结果通常是一样的,但格式补丁管到上午方法从来没有发现重命名的文件。这使得格式补丁式的速度更快,但没有那么好。