我有一个名为demo
的分支,我需要将其与master
分支合并。我可以使用以下命令获得所需的结果:
git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master
我唯一关心的是,* 如果有任何合并问题 *,我想告诉git
覆盖master
分支中的更改,而不给我合并提示。所以基本上demo
分支中的更改应该自动覆盖master
分支中的更改。
我环顾四周,有多种选择,但我不想冒险合并。
6条答案
按热度按时间jhdbpxl91#
与这个答案没有太大关系,但我会放弃
git pull
,它只运行git fetch
,然后是git merge
。你正在做三次合并,这将使你的Git运行三次fetch操作,而你只需要一次fetch操作。因此:控制最棘手的合并
这里最有趣的部分是
git merge -X theirs
。作为root545 noted,-X
选项被传递给合并策略,默认的recursive
策略和替代的resolve
策略都采用-X ours
或-X theirs
(一个或另一个,但不是两个)。然而,要理解它们的作用,你需要知道Git如何发现和处理 * 合并冲突 *。当某个文件的 * 基本 * 版本既不同于 * 当前 *(也称为本地、HEAD或
--ours
)版本 ,也不同于 * 另一个(也称为远程或--theirs
)版本时,可能会在某个文件中发生合并冲突1。也就是说,合并已经确定了三个修订(三个提交):基地我们的还有他们的“base”版本来自我们的commit和他们的commit之间的 merge base,如commit graph中所示(关于这方面的更多信息,请参阅其他StackOverflow帖子)。Git发现了两组变化:“我们做了什么”和“他们做了什么”。这些变化(一般)是在逐行, 纯文本 * 的基础上发现的。Git对文件内容没有真实的的理解;它仅仅是比较文本的每一行。这些变化就是您在
git diff
输出中看到的,并且一如既往,它们也有 context。有可能我们改变的东西和他们改变的东西在不同的线上,所以这些变化看起来不会发生冲突,但是上下文也发生了变化(例如:例如,由于我们的更改接近文件的顶部或底部,因此文件在我们的版本中耗尽,但在他们的版本中,他们也在顶部或底部添加了更多文本)。如果更改发生在 * 不同 * 行上-例如,我们在第17行将
color
更改为colour
,而他们在第71行将fred
更改为barney
-那么就没有冲突:Git只接受两个更改。如果更改发生在相同的行上,但是是 * 相同的 * 更改,Git会获取 * 一个副本 *。只有当更改在相同的行上,但是是不同的更改,或者是干扰上下文的特殊情况,您才会得到修改/修改冲突。-X ours
和-X theirs
选项告诉Git如何解决此冲突,只需选择以下两个更改之一:我们的,或者他们的。既然你说你要将demo
(他们的)合并到master
(我们的),并希望从demo
中得到更改,那么你需要-X theirs
。然而,盲目地应用
-X
是危险的。仅仅因为我们的更改在逐行的基础上没有冲突并不意味着我们的更改实际上没有冲突!一个经典的例子出现在带有变量声明的语言中。基础版本可能会声明一个未使用的变量:在我们的版本中,我们删除了未使用的变量以消除编译器警告-而在 * 他们的 * 版本中,他们在几行之后添加了一个循环,使用
i
作为循环计数器。如果我们将这两个更改结合起来,则生成的代码不再编译。-X
选项在这里没有帮助,因为更改在 * 不同的行 * 上。如果您有一个自动化的测试套件,那么最重要的事情就是在合并之后运行测试。您可以在提交后执行此操作,并在以后需要时进行修复;或者你也可以在提交前 * 执行,方法是在
git merge
命令中添加--no-commit
。我们将把所有这些细节留给其他帖子。1您还可以获得与“文件范围”操作有关的冲突,例如:例如,也许我们修复了文件中某个单词的拼写(这样我们就有了一个改变),而他们 * 删除 * 了整个文件(这样他们就有了一个删除)。不管
-X
参数如何,Git都不会自行解决这些冲突。执行更少的合并和/或更智能的合并和/或使用变基
在我们的两个命令序列中有三个合并。第一个是将
origin/demo
引入本地demo
(如果您的Git非常旧,则使用git pull
,将无法更新origin/demo
,但会产生相同的最终结果)。第二种是将origin/master
带入master
。我不清楚谁在更新
demo
和/或master
。如果您在自己的demo
分支上编写自己的代码,* 和 * 其他人正在编写代码并将其推送到origin
上的demo
分支,那么第一步合并可能会产生冲突,或者产生真实的的合并。通常情况下,最好使用rebase而不是merge来合并工作(诚然,这是品味和观点的问题)。如果是这样的话,您可能需要使用git rebase
。另一方面,如果你从来没有在demo
上做过任何自己的提交,你甚至不需要demo
分支。或者,如果你想自动化很多这样的事情,但又能仔细检查你和其他人是否都提交了,你可能想使用git merge --ff-only origin/demo
:如果可能的话,这将快进你的demo
以匹配更新的origin/demo
,如果不匹配,则直接失败(此时你可以检查两组更改,并选择一个真实的的合并或适当的变基)。同样的逻辑也适用于
master
,尽管您是在 *master
上进行合并,所以您肯定需要一个master
。然而,如果不能以快进非合并的方式完成合并,那么您更有可能希望合并失败,因此这可能也应该是git merge --ff-only origin/master
。假设你从来没有在
demo
上做过自己的提交。在这种情况下,我们可以完全丢弃名称demo
:如果你正在做你自己的
demo
分支提交,这是没有帮助的;你也可以保留现有的合并(但可能添加--ff-only
,这取决于你想要的行为),或者切换到做一个变基。请注意,所有三种方法都可能失败:merge可能会因冲突而失败,使用--ff-only
的merge可能无法快进,而rebase可能会因冲突而失败(rebase本质上是通过 cherry-picking commits工作的,它使用了merge机制,因此可能会产生合并冲突)。8i9zcol22#
我有一个类似的问题,我需要有效地替换任何文件,有更改/冲突与不同的分支。
我找到的解决方案是使用
git merge -s ours branch
。请注意,选项是
-s
,而不是-X
。-s
表示使用ours
作为顶级合并策略,-X
将对recursive
合并策略应用ours
选项,这不是我(或我们)在这种情况下想要的。步骤,其中
oldbranch
是要用newbranch
覆盖的分支。git checkout newbranch
检出要保留的分支git merge -s ours oldbranch
在旧分支中合并,但保留我们所有的文件。git checkout oldbranch
检出要覆盖的分支get merge newbranch
在新分支中合并,覆盖旧分支de90aj5v3#
这种合并方法将在
master
之上添加一个提交,它将粘贴feature
中的任何内容,而不会抱怨冲突或其他垃圾。在你触摸任何东西之前
现在准备master
把
feature
打扮好去杀戮
hvvq6cgz4#
这些命令将帮助将
demo
分支的代码覆盖到master
拉取本地
demo
分支现在 checkout
master
分支。此分支将与demo
分支上的代码完全更改停留在
master
分支,运行此命令。reset
表示您将重置当前分支--hard
是一个标志,表示它将被重置,而不会引发任何合并冲突origin/demo
将被视为强制覆盖当前master
分支的分支以上命令的输出将显示
origin/demo
或demo
分支上的最后一条提交消息
最后,强制将
master
分支上的代码推送到远程存储库。ercv8c1e5#
你可以在git merge中尝试“我们的”选项
git merge分支-X our
这个选项通过支持我们的版本来强制冲突的大块被干净地自动解决。来自另一棵树的与我们这边不冲突的更改将反映到合并结果中。对于二进制文件,整个内容都来自我们这边。
vuktfyat6#
当我尝试使用
-X theirs
和其他相关的命令开关时,我一直得到一个合并提交。我可能没有正确理解。一个容易理解的替代方法是删除分支,然后再次跟踪它。这并不完全是一个“合并”,但这正是我遇到这个问题时所寻找的。在我的例子中,我想从一个被强制推送的远程分支中拉取更改。
你可以在不删除你自己的分支的情况下做到这一点,这很好,使用
git reset
:另一个SO帖子更详细地描述了here。