【问题标题】:How can I preview a merge in git?如何在 git 中预览合并?
【发布时间】:2011-08-14 15:01:01
【问题描述】:

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

为了决定我是否真的要合并这个分支,我想看看合并将做什么的某种预览。最好能够查看正在应用的提交列表。

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

【问题讨论】:

  • 如果我不喜欢这个结果,我会选择 git mergegit reset --keep HEAD@{1}
  • 请注意,查看提交列表及其差异并不一定能说明全部情况 - 如果合并不重要,尤其是存在冲突时,合并的实际结果可能是有点意思。
  • 您的原始方法正是这样做的。我的评论的重点是,尽管查看单个差异都很好,但如果您有一个复杂的合并,即使所有合并的提交都独立良好,您最终可能会得到令人惊讶的结果。
  • @Jan:由于某些原因,git reset --keep HEAD@{1} 返回了fatal: Cannot do a keep reset in the middle of a merge. 帮助?
  • 为什么 git-merge 中没有 --preview 选项?

标签: git git-merge


【解决方案1】:
  • git log ..otherbranch
    • 将合并到当前分支的更改列表。
  • git diff ...otherbranch
    • 从共同祖先(合并基础)到将被合并的头部的差异。 注意三个点,与两个点相比,它们具有特殊含义(见下文)。
  • gitk ...otherbranch
    • 自上次合并以来分支的图形表示。

空字符串意味着HEAD,这就是为什么只使用..otherbranch 而不是HEAD..otherbranch

两个点和三个点对于 diff 的含义与列出修订的命令(log、gitk 等)的含义略有不同。对于 log 和其他,两个点 (a..b) 表示在 b 但不在 a 中的所有内容,三个点 (a...b) 表示仅在 ab 之一中的所有内容。但是差异适用于两个修订版,并且由两个点 (a..b) 表示的更简单的情况是从 ab 的简单差异,三个点 (a...b) 表示共同祖先和 b (@ 987654338@)。

【讨论】:

  • 第三个点是我遗漏的部分,谢谢!日志方法也很有效, log -p --reverse ..otherbranch 似乎是查看合并内容的好方法。
  • 在我尝试这个之前我错过了git checkout master。我想知道为什么它说我的所有更改都将被覆盖......
  • git show ..otherbranch 将显示将合并到当前分支的更改和差异列表。
  • 这并不完全准确,尤其是樱桃采摘。
  • @void.pointer,git 不会在正常合并中专门处理cherry-picks,所以它也不在这里。可以编写一个合并策略,但据我所知,从来没有。
【解决方案2】:

我发现最适合我的解决方案是只执行合并并在出现冲突时中止它。这种特殊的语法对我来说感觉干净简单。这是下面的策略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 现在更像是一个说明,如果合并存在您尚未准备好处理的冲突,您可以简单地中止合并。如果阅读 cmets,请记住!]

【讨论】:

  • +1 表示策略 2。临时分支,准确显示合并时将进入的内容。对于这种特殊情况,我要避免使用策略 1。
  • 我建议改变策略,以便首先使用更安全的策略(我的心理训练通过了 - 大多数人会认为最好的选择是第一个,尽管明确使用了“更安全”这个词) 但除此之外,工作非常出色。
  • 如果您不想直接提交更改,可以使用git merge --no-ff --no-commit。这消除了对不同分支的“需求”,使得审查更改变得更容易,imo。
  • 如果您决定根本不想合并,实际上宁愿编写更多代码然后提交到您的分支,这样您就可以在测试服务器上部署您的分支,不会'你还需要恢复git merge --no-ff --no-commit吗?如果你不喜欢你看到的东西,我想你仍然可以在那之后做一个git merge --abort?即使合并不会产生冲突?
  • 大部分人喜欢复制粘贴,不去想太多。因此,对于策略 1,也许还要在临时本地分支 git reset --hard HEAD 中添加如何中止合并,然后签出不同的分支 git checkout <different branch name> 并删除临时分支 git delete -b <name of temporary branch>
【解决方案3】:

如果你像我一样,你正在寻找等同于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 与建议“合并然后中止”的顶级解决方案相比,该解决方案更容易且更不容易出错(因此风险也更低)。

【讨论】:

  • 应该是$ git checkout target-branch,然后是$ git diff --name-status ...branch-to-be-merged(三个点是必不可少的,所以按原样输入)
  • 缺少一件事:它不会显示哪些文件会发生冲突——它们与已在分支上修改但可以合并的文件具有相同的“M”标记任何冲突。
  • 也许 2012 年的情况有所不同,但现在中止合并似乎相当可靠,所以我认为现在将其描述为“更容易且更不容易出错”是不公平的。跨度>
【解决方案4】:

这里的大多数答案要么需要干净的工作目录和多个交互式步骤(不利于脚本编写),要么不适用于所有情况,例如过去的合并已经将一些未完成的更改带入您的目标分支,或者樱桃挑选做同样的事情。

要真正了解如果您将 develop 合并到 master 分支中会发生什么变化,现在:

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 提供链接)

附:

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

$ 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 变得困难。小心。

【讨论】:

  • @hraban 这看起来是正确的答案,但显然仍然缺少一个元素。这种方法要求用户“目测”输出以查看是否存在冲突标记。您是否有一种方法,如果存在冲突,则仅返回 true,如果没有冲突,则返回 false(例如,不需要“眼球”测试或任何人为干预的布尔值)。
  • @dreftymac 找不到任何有这种效果的东西。你可以使用git merge-tree ... | grep -q '^[a-z].*in both$' &amp;&amp; echo conflict || echo safe to merge 之类的东西,但它是 finnicky;我可能忘记了一个案例。也许您想检查冲突标记,而不是?例如这可能不会捕捉到“他们的删除,我们的改变”的风格冲突。 (我刚刚检查过,它甚至没有显示冲突标记,所以你需要一个细致的正则表达式才能在这里安全)
  • 使用less -R 处理彩色输出而不修改您的配置。
  • 这是唯一正确的答案。现在确定为什么其他人被赞成。
【解决方案5】:

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

git log ...@{u}

我相信这需要 git 1.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”来显示补丁(即“差异”),“git incoming --pretty=oneline”,以获得简洁的总结,等等。然后您可以(可选)运行“git pull”来实际合并。 (不过,既然你已经获取了,那么可以直接进行合并。)

    同样,“git outgoing”显示如果您运行“git push”会推送什么。

    【讨论】:

    • “许多答案都省略了获取” - 那是因为问题是关于合并预览;不要拉或推。合并之前不需要 fetch,除非在 pull 的特定情况下(尽管当合并到远程存在的分支时,首先拉取该分支通常是个好主意,以确保您有最新的它的版本)。
    • 如果您仔细阅读您的评论,您会发现您将“pull”与“merge”和“fetch”混为一谈,这很常见,但在区分很重要时会混淆(就像这里一样)。 stackoverflow.com/a/292359/127971
    • =2, "conflate" - 很酷的词! :) 我真的很喜欢你的回答,它显示了一个合并预览的用例,有些人可能会觉得有帮助。现在,如果您重新阅读该问题,然后我对您的回答发表了第一条评论,您可能会注意到我完全打算强调拉动(本质上只是一个提取,然后是一个合并)是您唯一需要在预览或应用合并之前完全需要获取。并且 OP 只专门询问了合并部分,除了更新本地分支并对其远程对应部分进行更改之外,它还有许多用例。
    【解决方案7】:

    git log currentbranch..otherbranch 会给你一个提交列表,如果你进行合并,这些提交将进入当前分支。提供有关提交详细信息的 log 通常参数将为您提供更多信息。

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

    这些会有帮助吗?

    【讨论】:

    • 其实错了。 git log otherbranch..currentbranch 给出了 currentbranch 上的提交列表。 git diff otherbranch currentbranch 为您提供了从待合并版本到当前提示的差异,这几乎是无用的,因为您想要的是从合并基础到合并头的差异。
    • 谢谢。我已经把树的名字换了。
    【解决方案8】:

    实际上没有以一次性方式执行合并(请参阅 Kasapo 的回答),似乎没有一种可靠的方式来看待这一点。

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

    git log TARGET_BRANCH...SOURCE_BRANCH --cherry
    

    这可以公平地表明哪些提交将进入合并。要查看差异,请添加 -p。要查看文件名,请添加--raw--stat--name-only--name-status 中的任何一个。

    git diff TARGET_BRANCH...SOURCE_BRANCH 方法的问题(参见 Jan Hudec 的回答)是,如果您的源分支包含交叉合并,您将看到目标分支中已有更改的差异。

    【讨论】:

      【解决方案9】:

      Pull Request - 我已经使用了大部分已经提交的想法,但我也经常使用的一个是(特别是如果它来自另一个开发人员)做一个 Pull Request,它提供了一种方便的方法来审查合并中的所有更改在它发生之前。我知道这是 GitHub 而不是 git,但它确实很方便。

      【讨论】:

        【解决方案10】:

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

        【讨论】:

          【解决方案11】:

          我不想使用 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
          

          以下是一些关于我为什么对针对这些特定文件感兴趣的讨论:

          How can I trust Git merge?

          https://softwareengineering.stackexchange.com/questions/199780/how-far-do-you-trust-automerge

          【讨论】:

            【解决方案12】:

            我试过这个东西来查看 Visual Studio 代码的变化。

            从 dev 创建一个临时分支。然后将更改文件的分支与 --no-ff --no-commit 标志合并。

            git checkout dev 
            git checkout -b feature_temp 
            git merge feature --no-ff --no-commit
            

            您的功能分支的更改文件将反映在 feature_temp 分支中。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-09-15
              • 2013-10-06
              • 1970-01-01
              • 2022-01-13
              • 1970-01-01
              • 1970-01-01
              • 2021-08-21
              • 2015-04-09
              相关资源
              最近更新 更多