所以我和我的团队正在敏捷开发过程中开展一个项目。每次迭代都有test
分支的几个分支。每个分支充当迭代的任务。迭代完成后,所有任务分支都合并到test
分支中,test
分支合并到master
。
我遇到的问题是将test
合并到master
。在这种特定情况下,master
完全落后,test
包含许多文件甚至不包含在master
中。因此,当我通过拉取请求比较test
和master
时,其行为就像test
中的所有新文件都不会添加到master
。
这是git-merge的工作原理吗?它只更新master
中更改的文件而不关心添加的文件?
这是我做git-rebase的唯一选择吗?如果是这样,那怎么办?
编辑:我可能已找到问题的根源。如果某些任务分支在迭代开始时从master
分支出来,然后在最后合并到test
,该怎么办?将test
合并到master
时会导致一些问题吗?每当我在Github上查看我的test
分支时,它会说:“这个分支是7个提交,5个提交在主人之后”。
答案 0 :(得分:1)
根据您的编辑,我们将其分为两部分。
首先,您直接询问git操作应该如何表现:
这是git-merge的工作原理吗?它只更新master中已更改的文件,并不关心添加的文件?
没有;合并时应包含远程分支上的任何更改 - 包括添加新文件。如果没有发生这种情况,还会发生其他事情。
这是我做git-rebase的唯一选择吗?
基于边缘情况的几个例外,您应该期望结果内容(TREE
)对于rebase与合并相同。无论是什么使得合并不按预期执行,可能也导致rebase以意想不到的方式运行。
拒绝或合并的选择(理论上)只是关于如何保留历史。
第二:好的......那么这里到底发生了什么?
很难说完全正在发生什么,因为很难获得有关回购当前状态的足够信息。但我可以制定一些场景,并谈谈合并是如何工作的,也许这会让你足够继续,你可以解决它... ...
假设你发起这样的合并:
git checkout branchA
git merge branchB
现在git
将确定三个提交:
branchA
指向的内容)所以,如果你有
A -- B -- C -- D -- O <--(branchA)
\
E -- F -- T <--(branchB)
然后O
将我们的,T
将他们的,B
将 base
下一个git会在B
和T
之间计算一个补丁(大致差异) - 我们可以调用它们#34;他们的变化&#34; - 以及B
和O
之间的补丁 - 我们可以致电&#34;我们的更改&#34;。
如果提交E
添加了以前不存在的文件foo.txt
,那么我们的更改中不会对该文件进行任何更改(因为它在B
中都不存在或O
),但foo.txt
将在其更改中成为新文件(因为它在B
中不存在但在T
中确实存在。)< / p>
现在git想要创建一个包含我们的更改及其更改的组合补丁。如果我们的更改及其更改都尝试修改相同的代码块,则可能会出现冲突。但在我们的&#34;新文件&#34;因为我们的更改没有提及foo.txt
,所以不会发生冲突。合并后的补丁应包含&#34;新文件foo.txt
&#34;使用T
上显示的文件内容。
所以大部分时间,如果merge
表现得很混乱,你可以通过了解用作合并基础的内容来开始理解它。
git merge-base branchA branchB
将打印出提交ID。问题是,提交是否包含foo.txt
?如果确实如此,那么你就不会得到你期望的行为;然后将问题简化为&#34;找出计算出的合并库包含foo.txt
的原因。
现在在上面的示例中,此命令将返回B
的ID,该ID不包含foo.txt
。那么为什么你的情况会有所不同呢?
在编辑中,您描述了一些分支是从master创建的并合并到测试中。这不一定是个问题。说我们有
A -- B <--(master)
你说
git checkout master
git branch test
然后在test
上进行了一些工作。
A -- B <--(master)
\
C -- D <--(test)
现在有人创建了一个任务分支,但他们是从master
创建的。
A -- B <--(master)
|\
| E -- F <--(task1)
\
C -- D <--(test)
然后他们将task
合并到test
A -- B <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
其他一些影响正在影响master
A -- B -- G -- H -- O <--(master)
|\
| E ----- F <--(task1)
\ \
C -- D -- T <--(test)
现在,在这种情况下,task1
创建了master
&#34;来自git
&#34;无所谓。事实上,master
甚至中当前存储的内容都反映了它是从test
创建的事实。它也可以在提交C
之前从task1
创建。
意味着合并仍然可以正常工作。
但这是一个不同的场景......如果从master
创建master
的人在意识到他们需要分支之前实际提交了更改A -- B <--(master)
\
C -- D <--(test)
该怎么办?所以在这种情况下,我们再次从
task1
并且开发人员开始在master
上编码A -- B -- E <--(master)
\
C -- D <--(test)
。他们承诺,而你啊
master
然后有人说&#34;嘿,老兄,你不能直接在git checkout master
git checkout -b task1
# work continues on the task1 branch
git commit
&#34;上工作,所以我们试着解决问题。
master
其他一些工作发生在A -- B -- E -- G <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
上,所以现在你有了
E
看起来相当不错,但有人说'嘿,我们无法在master
上test
进行更改,直到git checkout master
git revert HEAD^
合并为止;而且我们无法承受历史重写会导致的问题。因此...&#34;
A -- B -- E -- G -- ~E <--(master)
\ \
\ F <--(task1)
\
C -- D <--(test)
我们有
A -- B ------- E -- G -- ~E -- H -- O <--(master)
\ \
\ F <--(task1)
\ \
C -- D -- T <--(test)
每个分支上的所有内容都是正确的,因此继续工作
test
但是现在当你尝试将master
合并到git
时,会发生一些可怕的事情:E
认为合并基数为master
,因为test
之间存在共同的祖先{1}}和E
,E
是可以覆盖所有其他人/任何其他人无法联系到的人。{/ p>
因此,以foo.txt
作为合并基础,他们的更改不会影响E
(因为它已在foo.txt
中创建),而我们的更改已删除~E
(在foo.txt
中)。因此合并结果没有master
,这不是分支的变化 - 它已经在{{1}}的历史记录中发生了变化 - 因此公关报告对此没有任何说明
我知道这究竟发生了什么吗?不,我敢打赌这是非常像这样的吗?是。我可以拼出一个修复程序吗?不是真的,因为可能涉及到确切的步骤并依赖完全发生的事情。
现在我首先尝试确认问题是否与我所建议的基本相同。
答案 1 :(得分:0)
git merge
合并了test
到master
的所有更改,即test
中已更改,添加和删除的文件将在master
中更改,添加或删除}。
您要采取的措施是:
git checkout master
git merge test
// if required: fix merge conflicts, shouldn't be required if `test` was in `sync` with master at the start of your sprint
git commit // if fixing merge conflicts were necessary
git push
在理想世界中,当master
和test
在sprint开始时同步并且所有内容都可以合并回来时,两个分支将在您的sprint结束时再次同步。您的工作流程类似于gitflow - 只有您拨打分支test
而不是develop
。
我的推荐:如果可能的话,当多个人在回购(分支)上工作时,请避免使用rebase。这是根据风险重写的历史。
github,TFS或VSTS等源代码管理工具也在合并而不是重新定位。