Git合并强制覆盖

rnmwe5a2  于 2023-04-28  发布在  Git
关注(0)|答案(6)|浏览(258)

我有一个名为demo的分支,我需要将其与master分支合并。我可以使用以下命令获得所需的结果:

git pull origin demo
git checkout master
git pull origin master
git merge demo
git push origin master

我唯一关心的是,* 如果有任何合并问题 *,我想告诉git覆盖master分支中的更改,而不给我合并提示。所以基本上demo分支中的更改应该自动覆盖master分支中的更改。
我环顾四周,有多种选择,但我不想冒险合并。

jhdbpxl9

jhdbpxl91#

与这个答案没有太大关系,但我会放弃git pull,它只运行git fetch,然后是git merge。你正在做三次合并,这将使你的Git运行三次fetch操作,而你只需要一次fetch操作。因此:

git fetch origin   # update all our origin/* remote-tracking branches

git checkout demo         # if needed -- your example assumes you're on it
git merge origin/demo     # if needed -- see below

git checkout master
git merge origin/master

git merge -X theirs demo   # but see below

git push origin master     # again, see below

控制最棘手的合并

这里最有趣的部分是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是危险的。仅仅因为我们的更改在逐行的基础上没有冲突并不意味着我们的更改实际上没有冲突!一个经典的例子出现在带有变量声明的语言中。基础版本可能会声明一个未使用的变量:

int i;

在我们的版本中,我们删除了未使用的变量以消除编译器警告-而在 * 他们的 * 版本中,他们在几行之后添加了一个循环,使用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

git fetch origin   # update origin/*

git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"

git merge -X theirs origin/demo || die "complex merge conflict"

git push origin master

如果你正在做你自己的demo分支提交,这是没有帮助的;你也可以保留现有的合并(但可能添加--ff-only,这取决于你想要的行为),或者切换到做一个变基。请注意,所有三种方法都可能失败:merge可能会因冲突而失败,使用--ff-only的merge可能无法快进,而rebase可能会因冲突而失败(rebase本质上是通过 cherry-picking commits工作的,它使用了merge机制,因此可能会产生合并冲突)。

8i9zcol2

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在新分支中合并,覆盖旧分支
de90aj5v

de90aj5v3#

这种合并方法将在master之上添加一个提交,它将粘贴feature中的任何内容,而不会抱怨冲突或其他垃圾。

在你触摸任何东西之前

git stash
git status # if anything shows up here, move it to your desktop

现在准备master

git checkout master
git pull # if there is a problem in this step, it is outside the scope of this answer

feature打扮好

git checkout feature
git merge --strategy=ours master

去杀戮

git checkout master
git merge --no-ff feature
hvvq6cgz

hvvq6cgz4#

这些命令将帮助将demo分支的代码覆盖到master

git fetch --all

拉取本地demo分支

git pull origin demo

现在 checkout master分支。此分支将与demo分支上的代码完全更改

git checkout master

停留在master分支,运行此命令。

git reset --hard origin/demo

reset表示您将重置当前分支
--hard是一个标志,表示它将被重置,而不会引发任何合并冲突
origin/demo将被视为强制覆盖当前master分支的分支
以上命令的输出将显示origin/demodemo分支

上的最后一条提交消息
最后,强制将master分支上的代码推送到远程存储库。

git push --force
ercv8c1e

ercv8c1e5#

你可以在git merge中尝试“我们的”选项
git merge分支-X our
这个选项通过支持我们的版本来强制冲突的大块被干净地自动解决。来自另一棵树的与我们这边不冲突的更改将反映到合并结果中。对于二进制文件,整个内容都来自我们这边。

vuktfyat

vuktfyat6#

当我尝试使用-X theirs和其他相关的命令开关时,我一直得到一个合并提交。我可能没有正确理解。一个容易理解的替代方法是删除分支,然后再次跟踪它。

git branch -D <branch-name>
git branch --track <branch-name> origin/<branch-name>

这并不完全是一个“合并”,但这正是我遇到这个问题时所寻找的。在我的例子中,我想从一个被强制推送的远程分支中拉取更改。
你可以在不删除你自己的分支的情况下做到这一点,这很好,使用git reset

git reset --hard origin/<branch-name>

另一个SO帖子更详细地描述了here

相关问题