如何在Git中手动合并所有文件?

104

我希望使用meld或其他差异工具手动合并所有文件,如何在Git中实现?
当我运行 git mergetool 时, 它显示 no files need merging。所以我想只有在出现冲突的情况下才能这样做。


3
我想合并文本文件 :) 我以前使用过mercurial手动合并,并喜欢同时查看3个文件,如果出现问题,我总是可以自己编辑它们。 - gennad
13
是的,有些情况下我想手动合并,因为在这种情况下我知道一切都会按照我的意愿进行,而不是应用程序决定的。 - gennad
1
自动合并并在发生问题时修复它们怎么样? - Tomasz Wysocki
据我所知,这种情况已经不可用了,当检测到冲突时,git不再允许自动合并。 - FanaticD
6
因为我无法知道是否出现了“被人类视为问题”的问题,我只能知道是否出现了“被Git视为问题”的问题。Git会自动合并文件,我无法勾选所有Git自动决策的结果。它可能会做出我不喜欢的特定更改。我希望在进行任何更改之前都能批准所有更改。 - cake
显示剩余4条评论
7个回答

125

有一个更简单的方法:

git merge --no-commit merge_branch

正如man所说:

--no-commit选项执行合并操作,但假装合并失败,不自动提交,让用户有机会检查和进一步调整合并结果后再提交。


7
谢谢。也许可以使用合并工具(mergetool)/meld以漂亮的三方界面逐个审查和合并更改吗? - James
21
如果添加 --no-ff,将禁用快进合并(fast forwarding),除非存在冲突。 - Løiten
当然,如果有冲突,请使用 git mergetool - Pluto
23
这仍然是一个自动合并,因此这并没有回答最初的问题。 - ThomasMcLeod

85

我有这样一个情况:

git merge --no-commit merge_branch 

刚刚触发了快进。

如果出现这种情况,您可以使用:

git merge --no-commit --no-ff merge_branch

然后您将能够审查您的更改。


1
能以同样的方式拉取吗?如果无法进行快进操作,我需要手动验证所有冲突。 - Maxim
1
@Maxim 不是的,因为 pull 只是 fetchmerge 的组合,所以首先调用 git fetch merge_branch,然后再执行 merge - Top-Master
使用 --no-commit --no-ff 的效果类似于在根目录下包含 *.gitattributes 文件,其中包含 -merge,但每个合并的选择是使用它还是不使用。 - Top-Master
4
当我运行命令时,出现了“Automatic merge went well; stopped before committing as requested”的提示。当我尝试运行“git mergetool”时,它显示“没有需要合并的文件”。 - Unknow0059
仅仅是推测,这种方法实际上就像从另一个源(例如从当前分支为“merge_branch”且干净的存储库中克隆)复制文件。在这种情况下,我只会期望 'git difftool' 显示任何更改。 - grenix

23

类似的问题是如何使用git防止自动合并?

FractalSpace给出了一个我认为很有用的答案:

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

这个想法是使用差异工具而不是自动合并工具手动选择需要的内容并创建新文件。


我已经添加了一个答案,将这个答案与“git merge”答案进行比较,以帮助澄清任何其他人进入此页面的问题。 - stevegt
当我尝试使用kdiff3或meld手动合并时,它会将更改保存到/tmp中的临时文件中,并不会更改工作目录。但是我需要将更改存储到工作目录中。 - porton
这里可能会丢失历史记录。对于Git,这可能只是在虚空中产生的巨大提交,而不像一个已合并的分支一样显示出来。 - Cutton Eye

18

如果你只需要微调一个合并的话,请跳转到下面的混合部分。

如果你对@True使用 git difftool 与其他使用 git merge 的答案之间的区别感到困惑,请查看Git mergetool vs difftool

以下是更多详细信息:

Difftool

如果你已经配置了git使用像kdiff3、meld或vimdiff这样的现代 diff.tool ,你就可以使用该diff工具手动合并,命令行可以很简单:

git difftool other_branch

这将让你在当前分支和其他分支之间进行双向手动合并(在man git-config中被描述为$LOCAL和$REMOTE)。

合并工具

其他答案所述的“正确”方法是配置git使用kdiff3或vimdiff作为您的merge.tool,并使用:

git merge --no-commit --no-ff other_branch
git mergetool

这个命令可以在$BASE、$LOCAL和$REMOTE之间执行N路手动合并,结果为$MERGED。请参见https://dev59.com/BHVC5IYBdhLWcg3w9GE9#2235841以获取有关如何配置git的示例。如果您使用git已知的工具之一,则可能根本不需要配置mergetool.*.cmd条目。(Meld只能显示三个窗格,因此如果您使用默认设置的meld,则将无法看到$ BASE。)

difftool与mergetool对比

也许会有人纠正我,但上述difftoolmergetool技术之间的主要区别似乎是:

  • mergetool可以进行N路合并(如果相应地进行配置)
  • mergetool将other_branch作为父项添加到新提交中,以便历史记录正确工作
  • difftool允许您手动查看和选择每个更改行,但您会失去用mergetool获得的上述两个优点

混合--融合最佳特点

一种结合合并和差异化的方法会像这样:

git merge --no-commit --no-ff other_branch
git mergetool
git difftool HEAD
git commit

...这将执行N路合并以解决冲突并使历史记录正确运作,然后显示完整的差异集,以便您在提交之前进行审查和调整。


当我尝试使用kdiff3或meld手动合并时,它会将更改保存到/tmp中的临时文件中,并不会更改工作目录。但是我需要将更改存储到工作目录中。 - porton
@porton 你可能需要进行更多的实验,但其中一个窗格应该是工作目录文件,或者应该是在退出后自动复制到工作目录的文件。我不记得是哪个了,这可能取决于你的git版本和工具配置。 - stevegt

11

我发现其他答案不太令人满意,因此在寻找答案时感到沮丧。我最终在这里找到了解决这个问题的方法:https://dev59.com/LGgv5IYBdhLWcg3wMN4U#11593308

如果你运行这些命令,你将创建一个新的提交,它基本上获取了branchToMergeFrom的最新提交,并允许你在其上应用补丁,这类似于在其上进行了额外的提交。

git checkout branchToMergeTo
git checkout --patch branchToMergeFrom [file]
你将会被提示(逐个文件如果你没有指定file),让你选择要合并的每个“块”。以这种方式引导你完成原本应该是自动合并过程的每一步,而是要求你在mergefrom分支中手动仲裁哪些部分需要接受。以下是我项目中它的一个例子:
@@ -249,7 +251,8 @@ def draw_everything():
  
     draw_bg()
     draw_balls(ax)
-    plt.show(block=False)
+    if show:
+        plt.show(block=False)
 
 def advance(ms, accel_fun, collision_matrix_fun):
     global balls
(3/6) Apply this hunk to index and worktree [y,n,q,a,d,K,j,J,g,/,e,?]?

在键入y<Enter>之后,我被呈现出该文件的下一个块:(4/6)。底部的提示让您可以使用y简单地接受合并的“块”,使用n拒绝它,甚至手动编辑它。以下是选项:

y - apply this hunk to index and worktree
n - do not apply this hunk to index and worktree
q - quit; do not apply this hunk or any of the remaining ones
a - apply this hunk and all later hunks in the file
d - do not apply this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

我想手动编辑一个代码块,因为我不想完全接受或拒绝合并。所以我选择了 e,然后得到了一个文件进行编辑。当我注意到底部甚至有关于如何正确编辑代码块的说明时,我感到很高兴。你甚至可以使用s选项将代码块分割成更小的块。

如果你想要手动合并,同时仍尽可能利用自动合并过程,我建议使用这个方法。区别在于,您可以查看每个合并的‘块’并按照自己的意愿进行编辑。希望这能帮助未来的读者。

在此过程之后,您可能需要运行 git checkout branchToMergeTo && git merge branchToMergeFrom 以正式将branchToMergeFrom的历史记录合并到branchToMergeTo中。


8

1

我选择策略ours(在TortoiseGit中也存在这个选项),在手动进行差异比较后,您可以手动引入所需更改。

From: https://git-scm.com/docs/merge-strategies

合并机制(git merge和git pull命令)允许选择后端“合并策略”使用-s选项。一些策略也可以采用自己的选项,可以通过给git merge和/或git pull传递-X参数来传递。
ours
这将解决任意数量的分支,但合并的结果树始终是当前分支头的树,实际上忽略了所有其他分支的更改。它旨在用于取代侧分支的旧开发历史。请注意,这与“递归”合并策略的-Xours选项不同。
然而,Bitbucket稍后看到的是一个谜,它将提交识别为合并,但未能实际合并分支(未解决拉取请求)-可能是Bitbucket guru可以帮助解决此问题,我甚至无法提供任何日志/错误消息,因为我没有那种可见性-git / TortoiseGit却完全没有抱怨。

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