如何在git中预览合并?


397

我有一个git分支(例如,主线),我想合并到另一个开发分支。还是我

为了确定我是否真的要合并该分支,我想预览一下合并的功能。最好具有查看正在应用的提交列表的能力。

到目前为止,我能想到的最好的是merge --no-ff --no-commit然后diff HEAD


17
我愿意git mergegit reset --keep HEAD@{1}如果我不喜欢这个结果。
Jan Hudec

3
请注意,查看带有差异的提交列表并不一定能说明整个问题-如果合并是不平凡的,特别是如果存在冲突,合并的实际结果可能会有点有趣。
卡斯卡贝尔2011年

2
您的原始方法正是这样做的。我的评论的重点是,尽管查看单个差异非常好,但是,如果您具有复杂的合并,即使所有合并的提交都是独立的,您也可能会得到令人惊讶的结果。
卡斯卡贝尔2011年

2
@Jan:出于某些原因,git reset --keep HEAD@{1}返回了fatal: Cannot do a keep reset in the middle of a merge.帮助?
moey 2012年

3
为什么--previewgit-merge中没有选项?
盖伊2014年

Answers:


283

我发现最适合我的解决方案是只执行合并,如果有冲突则中止合并。对我来说,这种特殊的语法感觉很简洁。这是下面的策略2

但是,如果要确保不弄乱当前分支,或者无论冲突是否存在,都还没有准备好合并,只需在其上创建一个新的子分支并将其合并:

策略1:安全的方法–合并临时分支机构:

git checkout mybranch
git checkout -b mynew-temporary-branch
git merge some-other-branch

这样,如果您只想查看冲突是什么,则可以简单地丢弃临时分支。您无需费心“中止”合并,就可以返回工作了—只需再次签出“ mybranch”,您就不会在分支中拥有任何合并的代码或合并冲突。

这基本上是空转。

策略2:当您确实要合并时,但仅当没有冲突时

git checkout mybranch
git merge some-other-branch

如果git报告冲突(并且仅在存在冲突的情况下),您可以执行以下操作:

git merge --abort

如果合并成功,则无法中止合并(仅重置)。

如果您还没有准备好合并,请使用上面的更安全的方法。

[编辑:2016年11月-我将策略1换成2,因为似乎大多数人都在寻找“安全的方法”。现在,策略2更应注意,如果合并中有尚未准备好应对的冲突,则可以简单地中止合并。如果阅读评论,请记住!]


2
策略2的+1。临时分支,确切显示合并时的内容。策略1是我要针对此特定情况避免的策略。
Gordolio

2
我建议改变策略以使更安全的方法成为第一(我的心理训练正在进行中,尽管清楚地使用了“更安全”一词,但大多数人会认为最好的选择将是第一选择),但除此之外,还不错工作。
paxdiablo

6
你可以做git merge --no-ff --no-commit,如果你不想直接提交更改。这消除了对另一个分支的“需求”,从而使查看更改变得更加容易了,imo。
Gerard van Helden

如果您决定根本不希望合并,并且实际上宁愿再编写一些代码然后提交到分支,以便可以在测试服务器上仅部署分支,就不必还原git merge --no-ff --no-commit吗?git merge --abort如果您不喜欢自己看到的内容,我想您仍然可以在那之后进行?即使合并不会产生冲突?
卡萨波,2016年

大多数人喜欢复制和粘贴,而不想太多。因此,对于策略1,也许还可以添加如何在临时本地分支中终止合并git reset --hard HEAD,然后签出其他分支git checkout <different branch name>并删除临时分支git delete -b <name of temporary branch>
user3613932 '17

400
  • git log ..otherbranch
    • 将合并到当前分支的更改列表。
  • git diff ...otherbranch
    • 从共同祖先(合并基础)到将要合并的内容的头的差异。请注意三个点,与两个点相比,它们具有特殊含义(请参见下文)。
  • gitk ...otherbranch
    • 自上次合并以来分支的图形表示形式。

空字符串表示HEAD,所以这就是为什么..otherbranch而不是HEAD..otherbranch

两个点与三个点对diff的含义与列出修订版本的命令(log,gitk等)的含义略有不同。对于log和其他符号,两个点(a..b)表示其中的所有内容,b但不是a,三个点(a...b)表示仅其中一个a或所有的内容b。但是diff适用于两个修订版本,用两个点(a..b)表示的更简单的情况是与ato的简单差异,b而三个点(a...b)表示共同祖先和bgit diff $(git merge-base a b)..b)之间的差异。


7
第三点是我缺少的部分,谢谢!日志方法很奏效还,登录-p --reverse ..otherbranch似乎是一个好办法,看看有什么会在被合并。
Glenjamin

1
git checkout master在尝试之前,我不见了。我想知道为什么它说我的所有更改都将被覆盖……
Droogans 2013年

5
git show ..otherbranch将显示将合并到当前分支的更改和差异列表。
盖伊2014年

4
这并不完全准确,尤其是对于樱桃采摘。
void.pointer

2
@ void.pointer,git在正常合并中不特别处理Cherry-pick,因此在这里也不会。可以编写一种合并策略,但是据我所知,从来没有。
Jan Hudec

19

如果您像我一样,就在寻找svn update -n。以下似乎可以解决问题。请注意,请务必先进行操作,git fetch以便您的本地存储库具有适当的更新以供比较。

$ git fetch origin
$ git diff --name-status origin/master
D       TableAudit/Step0_DeleteOldFiles.sh
D       TableAudit/Step1_PopulateRawTableList.sh
A       manbuild/staff_companies.sql
M       update-all-slave-dbs.sh

或者,如果您想从头部到遥控器进行比较:

$ git fetch origin
$ git diff origin/master

与IMO提出“合并然后中止”的顶级解决方案相比,IMO此解决方案更容易且出错的风险也更少(因此风险也更低)。


1
应该是$ git checkout target-branch然后$ git diff --name-status ...branch-to-be-merged(三个点是必不可少的,因此请按原样键入)
Lu55

它缺少一件事:它不会向您显示哪些文件存在冲突-它们与在分支上已修改但可以合并而没有任何冲突的文件具有相同的“ M”标记。
peterflynn

也许在2012年情况有所不同,但是最近几天中止合并似乎是很可靠的,所以我认为现在将其描述为“更容易,更不易出错”是不公平的。
David Z

8

此处的大多数答案都需要一个干净的工作目录和多个交互步骤(不利于脚本编写),或者不适用于所有情况,例如,过去的合并已将一些出色的更改带入目标分支,或者执行了相同。

要真正了解master分支合并后的变化develop,现在:

git merge-tree $(git merge-base master develop) master develop

由于这是一个管道命令,它不能猜测您的意思,因此必须明确。它还不会使输出着色或使用您的寻呼机,因此完整的命令应为:

git merge-tree $(git merge-base master develop) master develop | colordiff | less -R

https://git.seveas.net/previewing-a-merge-result.html

(感谢David Normington提供的链接)

PS:

如果您遇到合并冲突,它们将在输出中显示出通常的冲突标记,例如:

$ git merge-tree $(git merge-base a b ) a b 
added in both
  our    100644 78981922613b2afb6025042ff6bd878ac1994e85 a
  their  100644 61780798228d17af2d34fce4cfbdf35556832472 a
@@ -1 +1,5 @@
+<<<<<<< .our
 a
+=======
+b
+>>>>>>> .their

@dreftymac用户是一个很好的观点:这使其不适合编写脚本,因为您不能轻易地从状态代码中捕获它。根据情况(删除或修改等),冲突标记可能会完全不同,这也使grep变得很难。谨防。


1
@hraban这看起来像是正确的答案,但是显然仍然缺少一个元素。这种方法要求用户“盯上”输出以查看是否存在冲突标记。您是否有一种方法可以true在存在冲突和false没有冲突的情况下简单地返回(例如,不需要“眼球”测试或任何人工干预的布尔值)。
dreftymac

1
@dreftymac无法找到任何效果。您可以使用类似的方法,git merge-tree ... | grep -q '^[a-z].*in both$' && echo conflict || echo safe to merge但这很严格;我可能忘记了一个案例。也许您想检查冲突标记,而不是?例如,这可能无法捕捉到“他们被删除,我们改变了”的样式冲突。(我只是检查了一下,甚至没有显示冲突标记,因此您需要使用细致的正则表达式来保证安全)
hraban

1
使用less -R处理彩色输出,而无需修改您的配置。
Giacomo Alzetta

感谢@GiacomoAlzetta,我已经更新了它。
hraban

6

如果您已经获取了更改,则我最喜欢的是:

git log ...@{u}

我相信这需要git1.7.x。该 @{u}符号是上游分支的“简写”,因此比通用git log ...origin/master

注意:如果使用zsh和扩展的glog之类的东西,则可能必须执行以下操作:

git log ...@\{u\}

6

除了现有答案外,还可以创建别名以在合并之前显示差异和/或日志。许多答案忽略了fetch在“预览”合并之前首先要完成的工作;这是一个别名,将这两个步骤组合为一个别名(模拟类似于mercurial的hg incoming/ outgoing

因此,以“ git log ..otherbranch”为基础,您可以将以下内容添加到~/.gitconfig

...
[alias]
    # fetch and show what would be merged (use option "-p" to see patch)
    incoming = "!git remote update -p; git log ..@{u}"

为了对称起见,可以使用以下别名显示在推送之前已提交和将要推送的内容:

    # what would be pushed (currently committed)
    outgoing = log @{u}..

然后,您可以运行“ git incoming”以显示很多更改,或运行“ git incoming -p”以显示补丁(即“ diff”),“ git incoming --pretty=oneline”以获取简短的摘要等。然后,(可选)运行“ git pull”以实际合并。(不过,由于您已经获取了数据,因此可以直接进行合并。)

同样,“ git outgoing”显示了如果要运行“ git push” 将被推送的内容。


3

git log currentbranch..otherbranch如果您进行合并,将为您提供将提交到当前分支的提交列表。log的常用参数提供了有关提交的详细信息,将为您提供更多信息。

git diff currentbranch otherbranch将为您提供两次提交之间的差异,这将成为一次。这将是一个差异,为您提供将要合并的所有内容。

这些会有帮助吗?


2
其实是错的 git log otherbranch..currentbranch给出currentbranch上的提交列表。这样可以git diff otherbranch currentbranch使您从要合并的版本到当前提示之间的差异几乎没有用,因为您想要的是从合并基础到合并头的差异。
Jan Hudec

谢谢。我已经切换了树名。
Noufal Ibrahim

3

Pull Request-我已经使用了大多数已经提交的想法,但是我经常使用的一个想法(尤其是来自另一个开发人员的想法)正在执行Pull Request,这提供了一种方便的方法,可以在合并之前检查合并中的所有更改地点。我知道GitHub不是git,但是它确实很方便。


2

缺少以扔掉的方式实际执行合并的方法(请参阅Kasapo的答案),似乎没有一种可靠的方法可以看到这种情况。

话虽如此,这是一个稍微接近的方法:

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

这样可以很好地表明哪些提交将使其合并。要查看差异,请添加-p。要查看文件名,添加任何的--raw--stat--name-only--name-status

这种git diff TARGET_BRANCH...SOURCE_BRANCH方法的问题(请参阅Jan Hudec的答案)是,如果源分支包含交叉合并,您将在目标分支中看到差异变化。


1

也许这可以帮助您? git-diff- tree-比较通过两个树对象找到的Blob的内容和模式


1

我不想将git merge命令用作查看冲突文件的前提。我不想进行合并,我想在合并之前发现潜在的问题-自动合并的问题可能对我隐藏了。我一直在寻找的解决方案是,如何让git吐出两个分支中已更改的文件列表,这些文件将来会相对于某些共同祖先合并在一起。有了该列表后,我就可以使用其他文件比较工具来进一步探查问题。我搜索了多次,但仍然没有在本地git命令中找到想要的东西。

这是我的解决方法,以防它对其他人有所帮助:

在这种情况下,我有一个名为QA的分支,自上一个产品版本以来,该分支已进行了许多更改。我们的最新生产版本标记为“ 15.20.1”。我还有另一个开发分支new_stuff,我想将其合并到QA分支中。QA和new_stuff都指向“遵循”(如gitk报告)的15.20.1标记。

git checkout QA
git pull
git diff 15.20.1 --name-only > QA_files
git checkout new_stuff
git pull
git diff 15.20.1 --name-only > new_stuff_files
comm -12 QA_files new_stuff_files

以下是一些引起我为何对这些特定文件感兴趣的讨论:

我如何信任Git合并?

/software/199780/how-far-do-you-trust-automerge

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.