Git合并与强制覆盖

Posted

技术标签:

【中文标题】Git合并与强制覆盖【英文标题】:Git merge with force overwrite 【发布时间】:2017-03-23 20:42:46 【问题描述】:

我有一个名为demo 的分支,我需要与master 分支合并。我可以通过以下命令得到想要的结果:

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

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

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

【问题讨论】:

git push -f origin master @MDXF: 可能我错了,但我不应该将-f 选项与merge 命令一起使用,而不是与push 命令一起使用 您可以同时尝试,看看哪种方法适合您 强制覆盖的解决方案见以下链接:***.com/a/42454737/984471 git-scm.com/docs/merge-strategies 【参考方案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 noted,-X 选项被传递给合并策略,默认的recursive 策略和替代的resolve 策略都采用-X ours-X theirs(一个或另一个,但不能同时)。不过,要了解它们的作用,您需要了解 Git 如何发现和处理合并冲突

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

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

如果更改发生在不同行上——例如,我们在第 17 行将 color 更改为 colour,而他们在第 71 行将 fred 更改为 barney——那么就有没有冲突:Git 只接受 both 更改。如果更改发生在同一行,但相同更改,Git 会获取更改的一个副本。仅当更改在同一行,但更改不同,或者干扰上下文的特殊情况下,才会发生修改/修改冲突。

-X ours-X theirs 选项告诉 Git 如何解决此冲突,只需选择以下两个更改之一:我们的或他们的。既然您说您要将demo(他们的)合并到master(我们的)并希望从demo 进行更改,那么您将需要-X theirs

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

int i;

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

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


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


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

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

我不清楚是谁在更新demo 和/或master。如果您在自己的demo 分支上编写自己的代码, 其他人正在编写代码并将其推送到origin 上的demo 分支,那么这个第一步合并可能会发生冲突,或产生真正的合并。通常情况下,最好使用变基而不是合并来组合工作(诚然,这是一个品味和意见的问题)。如果是这样,您可能想改用git rebase。另一方面,如果您从未在demo 上进行任何自己的提交,那么您甚至不需要 demo 分支。或者,如果你想自动化很多,但能够仔细检查你和其他人何时提交,你可能想使用git merge --ff-only origin/demo:这将快进你的demo以匹配如果可能,更新 origin/demo,如果没有,则完全失败(此时您可以检查两组更改,并根据需要选择真正的合并或变基)。

同样的逻辑也适用于master,尽管您正在对master 进行合并on,所以您肯定需要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,具体取决于您想要的行为),或将其切换为进行变基。请注意,所有三种方法都可能失败:合并可能会因冲突而失败,与 --ff-only 合并可能无法快进,而变基可能会因冲突而失败(变基的工作原理本质上是 cherry-picking 提交,它使用合并机制,因此可能会发生合并冲突)。

【讨论】:

这是对 SO 上 anything 的最佳解释之一。特别是,-X ours-X theirs 的故障和示例问题非常有帮助。谢谢! @JasonRStevensCFA x2。 SO中最好的解释之一。【参考方案2】:

我有一个类似的问题,我需要有效地替换任何与不同分支发生更改/冲​​突的文件。

我找到的解决方案是使用git merge -s ours branch

请注意,选项是-s 而不是-X-s 表示将ours 用作***合并策略,-Xours 选项应用于recursive 合并策略,这不是我(或我们)在这种情况下想要的。

Steps,其中oldbranch 是您要使用newbranch 覆盖的分支。

git checkout newbranch 签出你想保留的分支 git merge -s ours oldbranch 合并到旧分支中,但保留我们所有的文件。 git checkout oldbranch 签出你要覆盖的分支 get merge newbranch 合并到新分支,覆盖旧分支

【讨论】:

注意:这里没有其他解决方案对我有用,因此我发布了我的答案。 它对我不起作用。它解决了冲突(解决了冲突的文件),但文件没有合并。也不能合并。 如果有人碰巧卡在提示您“请输入提交消息以解释为什么需要此合并”的地方:输入您的消息,然后按键盘上的 ESC 键,输入 :wq并按 ENTER 退出提示。 感谢@NiallMccormack 发布这个答案,它对我们帮助很大!【参考方案3】:

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

在你触摸任何东西之前

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

现在准备主人

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

【讨论】:

git push 完成 git-scm.com/docs/git-merge#Documentation/git-merge.txt-ours 。当提交没有干净地合并时,它起作用了。但是这种方法并不总是有效,引用源Changes from the other tree that do not conflict with our side are reflected in the merge result。它对我不起作用,因为我已经干净地合并了正在被覆盖的分支中的提交。有没有其他办法? 这对我有用!正是我想要的。 (我们曾尝试切换框架,但失败了。我们需要从糟糕的框架上挑选一些最近的工作,然后用我们挑选的分支覆盖 master 上的任何内容。)【参考方案4】:

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

git fetch --all

将您的demo 分支拉到本地

git pull origin demo

现在结帐到master 分支。这个分支将被demo分支上的代码完全改变

git checkout master

留在master 分支并运行此命令。

git reset --hard origin/demo

reset 表示您将重置当前分支

--hard 是一个标志,表示它将被重置而不会引发任何合并冲突

origin/demo 将被视为将强制覆盖当前master 分支的代码的分支

上述命令的输出将显示您在origin/demodemo 分支上的最后提交消息

然后,最后,将master 分支上的代码强制推送到您的远程仓库。

git push --force

【讨论】:

为什么使用远程'origin/demo'分支而不是本地'demo'分支。 @NevetsKuro 你也可以使用本地。如果使用“git fetch --all”获取最新提交并拉取分支“demo”,则“git reset --hard demo”和“git reset --hard origin/demo”都会导致相同的操作。跨度> 【参考方案5】:

您可以在 git merge 中尝试“我们的”选项,

git 合并分支 -X 我们的

此选项强制通过支持我们的版本来干净地自动解决冲突的大块。不冲突的其他树的更改 与我们这边都反映到合并结果上。对于二进制文件,全部内容都取自我们这边。

【讨论】:

这将是倒退的,因为 OP 说他希望 demo 版本成为首选,即使他正在合并到 master。还有-X theirs,但不清楚这是否是 OP 真正想要的。 你还没有读完。您的注释描述了 ours 在后端使用 -s 选项时的作用。当 ours-X 一起使用时:它会丢弃其他树所做的一切,声明我们的历史记录包含其中发生的一切。 source【参考方案6】:

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

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

这并不完全是“合并”,但这正是我遇到这个问题时所寻找的。就我而言,我想从远程分支中提取强制推送的更改。

【讨论】:

【参考方案7】:

我遇到了同样的问题,我找到了解决方案 here。在做任何事情之前不要忘记阅读documentation。

让我解释一下。假设我们有 2 个存储库 ma​​sterdevmaster,并且您想将 ma​​ster 替换为 devmaster。然后第一个命令如下

git checkout devmaster

现在您切换到 devmaster 分支。您需要与我们的合并(reference):

git merge -s ours master

然后签出代码:

git checkout master

下一阶段是,将 devmaster 合并到 ma​​ster

git merge devmaster

最后阶段是推送你的代码:

git push

但是请阅读所有文档,因为它适用于此。它不是 保证它也适用于您。

【讨论】:

以上是关于Git合并与强制覆盖的主要内容,如果未能解决你的问题,请参考以下文章

如何强制“git pull”覆盖本地文件?

如何退出GIT的rebase状态,强制覆盖本地代码

git强制覆盖

GIT用服务器上的版本强制覆盖掉本地的版本(转)

git强制覆盖更新

git分支覆盖合并,以及创新分支并且推送