小编典典

Git合并与强制覆盖

all

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

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

我唯一担心的是, 如果有任何合并问题
,我想告诉我git覆盖master分支中的更改而不给我合并提示。所以基本上demo分支中的更改应该自动覆盖master分支中的更改。

我环顾四周,有多种选择,但我不想冒险合并。


阅读 181

收藏
2022-08-05

共1个答案

小编典典

与这个答案并没有真正的关系,但我会放弃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
指出
的那样,-X选项被传递给合并策略,默认recursive策略和替代resolve策略都采用-X oursor -X theirs(一个或另一个,但不是两者)。但是,要了解它们的作用,您需要了解 Git 如何查找和处理 合并冲突

基本 版本与同一文件的 当前 (也称为本地、HEAD 或)版本
另一个(也称为远程或)版本不同时,某些文件1中可能会发生合并冲突。也就是说,合并已经确定了三个修订版(三个提交):base、ours 和
theirs。“基础”版本来自我们的提交和他们的提交之间的 合并基础 ,如提交图中所示(有关此内容的更多信息,请参阅其他 StackOverflow
帖子)。然后 Git 发现了两组变化:“我们做了什么”和“他们做了什么”。这些更改(通常)是逐行的, 纯文本的 --ours
--theirs __基础。 Git 对文件内容没有真正的理解;它只是比较每一行文本。

这些变化就是你在git diff输出中看到的,而且一如既往,它们也有 上下文
。我们更改的内容可能与它们更改的内容位于不同的行上,因此这些更改看起来不会发生冲突,但上下文也发生了变化(例如,由于我们的更改接近文件的顶部或底部,以便文件在我们的版本中用完,但在他们的版本中,他们还在顶部或底部添加了更多文本)。

如果更改发生在 不同 的行——或实例上,我们更改colorcolour第 17 行,然后它们更改fredbarney第 71
行——然后不存在冲突:Git 简单地接受 这两个 更改。如果更改发生在同一行,但是是 相同 的更改,Git 会 复制一份
更改。仅当更改位于同一行,但更改不同,或者干扰上下文的特殊情况下,您才会遇到修改/修改冲突。

和选项告诉 Git 如何解决这个冲突,只选择两个更改中的一个:我们的或他们的-X ours-X theirs既然您说您正在将demo(他们的)合并到master(我们的)并希望从 进行更改demo,那么您会想要-X theirs.

-X然而,盲目地申请是危险的。仅仅因为我们的更改没有逐行冲突并不意味着我们的更改实际上没有冲突!一个典型的例子发生在具有变量声明的语言中。基本版本可能会声明一个未使用的变量:

int i;

在我们的版本中,我们删除了未使用的变量以使编译器警告消失——在 他们的
版本中,他们在几行之后添加了一个循环,i用作循环计数器。如果我们结合这两个更改,生成的代码将不再编译。该-X选项在这里没有帮助,因为更改在
不同的行 上。

如果你有一个自动化测试套件,最重要的是在合并后运行测试。您可以在提交后执行此操作,并在需要时稍后修复;或者您可以 提交之前通过添加--no- commitgit merge命令来执行此操作。我们会将所有这些的详细信息留给其他帖子。


1您还可能会在“文件范围”操作方面发生冲突,例如,也许我们修复了文件中单词的拼写(以便我们进行更改),然后他们 删除
了整个文件(以便他们有删除)。-X无论争论如何,Git 都不会自行解决这些冲突。


进行更少的合并和/或更智能的合并和/或使用变基

我们的两个命令序列中都有三个合并。首先是origin/demo引入本地demogit pull如果您的 Git
非常旧,您的使用将无法更新origin/demo但会产生相同的最终结果)。二是origin/master带入master

我不清楚谁在更新demo和/或master. demo如果您在自己的分支上编写自己的代码,
其他人正在编写代码并将其推送到demo分支上origin,那么这个第一步合并可能会发生冲突,或者产生真正的合并。通常情况下,最好使用变基而不是合并来组合工作(诚然,这是一个品味和意见的问题)。如果是这样,您可能想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 可能会因冲突而失败,merge with--ff- only可能无法快进,rebase 可能会因冲突而失败(rebase 本质上是通过 挑选 提交来工作的,它使用合并机器,因此可能会发生合并冲突)。

2022-08-05