如何在 Git 中防止自动合并?

87

我想将一个本地分支合并到主分支,但不希望 Git 进行自动合并。我想要手动选择要合并到主分支的内容。

当使用 Git 的 difftool 命令时,我可以查看差异并选择要添加到主分支的内容。但是,当进行合并时,我之前选择的内容会丢失,因为 Git 会自动合并。我可以在合并之前将更改提交到主分支,但这样做似乎不自然。

而 Git 的 mergetool 仅在合并产生冲突时才可用。但如果 Git 进行自动合并,则通常没有冲突,因此无法运行 mergetool 命令。

更新:

我开始认为我的想法可能存在问题,或者根本不可能实现。也就是说,合并一个主题分支并仅合并我需要的内容,并在历史记录中反映这一点。无论如何,我提出的问题是在尝试使用 Git 时出现的。


这些你“事先选择”的更改是从哪里来的?它们是在你合并之前的工作树中进行的本地修改吗?你是想合并一个分支并仅保留其中的一些更改吗? - Cascabel
Jefromi,回答你的第一个问题,它们是从分支差异中产生的更改。这就是我在第二段第一句话中提到的。回答你的第二个问题,是的,它们是本地修改。这就是为什么如果我进行合并(没有先提交),我将失去这些差异。回答你的第三个问题,是的。我正在尝试合并一个分支,并通过使用差异工具(例如KDiff3)选择我想要的内容来保留其中的一些更改。 - marckassay
关于您的更新:如果您打算合并该分支的其余部分,这确实是不好的做法。一旦记录了合并,就表示您拥有了合并提交的内容。您当然可以继续您开始的操作-选择性地应用主题分支的几行差异,并直接提交这些差异(而不是作为合并)。如果您稍后合并整个主题,这应该(希望)不会导致冲突。 - Cascabel
1
请在此处接受一个答案。 - mega6382
5个回答

103

您想要绕过Git参与合并过程,手动选择每个修改文件的每一行进行合并。这不同于git cherry-pick。也不会有git merge --no-commit等命令帮助您。您需要执行以下操作:

$ git checkout master
$ git difftool -t kdiff3 local-branch HEAD

KDiff3窗口中,左侧(A)是您的本地分支,右侧(B)是您的当前分支(master)
从菜单中选择Merge | Merge Current File(或按下标题相同的彩色菱形图标)。
然后,您将看到每个文件的差异和冲突(如果有)。您可以选择左侧或右侧(AB),或两者都选,或手动调整合并后的文件。
另外,有些东西告诉我您的工作流程存在一些更大的问题。

2
选择作为答案! - Lordbalmon
4
如果你已经通过git config正确设置了自己的差异比较工具,那么kdiff3就不是必需的或有用的。 - digory doo
63
OP 的工作流程并没有必然的问题,他可能只是面临一个复杂的合并。Git 喜欢决定一些合并是“安全”的,并在实际上它们并不安全时悄悄地执行它们。 - Rag
9
当你遇到合并冲突时,你也在挑选和选择。如果你认为挑选和选择是一个有缺陷的过程,那么它不会比“最好情况”的自动合并更糟糕(甚至可能更好)。 - Apprentice Queue
7
徒弟队列,你没有理解重点。当Git进行合并且没有冲突时,你无法挑选任何内容。Git会自动合并文件,这正是提问者想要避免的。 - FractalSpace
显示剩余7条评论

27
git merge --no-commit --no-ff <local-branch>

它能做到。

当执行它时,将应用来自local-branch的更改,但尚未暂存。

然后,您可以查看要应用的更改,如果您想要全部接受,可以使用此方法应用它们。

git commit -a 
否则,选择要获取的文件,使用 git add 将它们加入到暂存区,最后使用 git commit 提交。如果需要恢复不想要的文件,则可以使用 git checkout -- 文件名 命令。

7
我尝试了那个命令,看起来它进行了自动合并并暂存了文件。在运行第一个命令后,我收到了以下消息:自动合并成功;按要求停止提交。 - marckassay
3
但是您可以使用 git reset HEAD 命令,然后使用 git add -p 命令选择您想要的内容。 - Cascabel
3
要完全关闭初始合并,请添加“-s ours”。 - jthill
3
我想实现相同的目标,在执行了 git merge --no-commit --no-ff <local-branch> 之后,我运行了 git reset HEAD。这样做可以将所有“待提交的更改”变为“未暂存的更改”。现在,通过使用 git diff 命令,我可以看到完整的差异,可以添加和提交我想要的更改,丢弃不需要的更改。 - Davide

9

如果您不信任自动合并,可能希望这样做,因为在文件中的两个不同位置上进行的编辑(这些编辑在不同分支上完成)可能不会引发自动合并引发冲突,但实际上可能无法一起工作。

您可能希望考虑使用自定义合并驱动程序。本页面描述了如何操作。

Git - 如何强制合并冲突并手动合并选定的文件

另一种选择是首先查找分支之间差异的文件,然后执行合并,然后将文件检出到适当的分支中,以确保您获得干净的合并和包含两个编辑之一的功能代码。

git diff --name-only <branch1> <branch2> 
git checkout <branch1> -- <paths>

3
这并不是不信任自动合并,而是它没有提供任何关于 Git 对文件所做更改的信息。我希望了解具体的更改情况。 - Scott Franco
我想一种方法是查看另一个分支上有哪些文件不同,然后检查每个文件的不同之处,再进行合并。查看另一个分支上不同的文件: git diff --name-only otherbranch查看特定文件在其他分支上的差异: git diff -p master someotherbranch -- the_specific_file.txt - andrew pate
当然,那是备选方案。我所说的是,git会给你一个消息“无法推送引用,请执行拉取”,然后如果你这样做,它会说“自动合并”(没有关于将要“自动合并”的详细信息)。这是一个糟糕的错误消息。 - Scott Franco

1

对于vim和vim-fugitive用户:

将以下内容添加到~/.gitconfig文件中

[difftool "fugitive"]
  cmd = vimdiff $LOCAL $MERGED $REMOTE
  trustExitCode = false
  keepBackup = false

现在使用 Fugitive 进行三向差异比较。
$ git checkout master
$ git difftool -t fugitive somebranch HEAD

关于$LOCAL、$MERGED和$REMOTE的说明:

$LOCAL是您正在合并的分支上的文件;当向您显示时,合并过程不会对其进行任何更改。

$MERGED是部分合并的文件,其中包含冲突;这是唯一被合并过程修改的文件,并且实际上在meld中从未向您显示。

$REMOTE是您正在合并的分支上的文件;当向您显示时,合并过程不会对其进行任何更改。


0

我认为你想要挑选个别的更改:

git checkout master
git log --reverse --oneline topic ^master

然后对于每个你想要在主分支中的提交,调用git cherry-pick

如果主题分支中剩余的更改应该被保留,你可能还想将此分支变基到新的主分支之上:

git rebase master topic

有趣的是,我从未听说过 cherry-pick 命令。我希望能够使用差异工具(例如 KDiff3)手动选择提交中的几行代码。但似乎这会合并整个提交。 - marckassay
1
如果您执行 git cherry-pick --no-commit; git reset HEAD,然后可以使用 git add -p 仅暂存您想要的内容。 - Cascabel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接