ChatGPT解决这个技术问题 Extra ChatGPT

如何在 git 中预览合并?

我有一个 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 选项?

s
scharette

git log ..otherbranch 将合并到当前分支的更改列表。

将合并到当前分支的更改列表。

git diff ...otherbranch 从共同祖先(合并基础)到将要合并的内容的头部的差异。请注意三个点,与两个点相比,它们具有特殊的含义(见下文)。

从共同祖先(合并基础)到将要合并的内容的头部的差异。请注意三个点,与两个点相比,它们具有特殊的含义(见下文)。

gitk ...otherbranch 自上次合并以来分支的图形表示。

自上次合并以来分支的图形表示。

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

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


第三个点是我缺少的部分,谢谢!日志方法也很有效, log -p --reverse ..otherbranch 似乎是查看合并内容的好方法。
在我尝试这个之前,我错过了 git checkout master。我想知道为什么它说我所有的更改都会被覆盖......
git show ..otherbranch 将显示将合并到当前分支的更改和差异列表。
这并不完全准确,尤其是对于樱桃采摘。
@void.pointer,git 在正常合并中不会特别对待樱桃挑选,所以它也不在这里。可以编写一个合并策略,但据我所知,从来没有。
C
Community

我发现最适合我的解决方案是执行合并并在发生冲突时中止它。这种特殊的语法对我来说感觉干净简单。这是下面的策略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 +1。临时分支,准确显示合并时将进入的内容。对于这种特殊情况,我试图避免使用策略 1。
我建议改变策略,以便首先使用更安全的策略(我的心理训练通过 - 大多数人会认为最好的选择是第一个,尽管明确使用了“更安全”这个词),但除此之外,非常好工作。
如果您不想直接提交更改,可以执行 git merge --no-ff --no-commit。这消除了对不同分支的“需求”,使得审查更改变得更容易,imo。
如果您决定根本不想合并,实际上宁愿编写更多代码然后提交到您的分支,这样您就可以在测试服务器上部署您的分支,您是否还需要恢复 { 1}?如果您不喜欢所看到的内容,我想您仍然可以在此之后执行 git merge --abort?即使合并不会产生冲突?
大多数人喜欢复制和粘贴,而不是想太多。因此,对于策略 1,也许还要添加如何在临时本地分支 git reset --hard HEAD 中中止合并,然后签出不同的分支 git checkout <different branch name> 并删除临时分支 git delete -b <name of temporary branch>
h
hraban

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

要真正了解如果将 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

(感谢大卫诺明顿的链接)

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 变得困难。谨防。


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

如果您像我一样,您正在寻找等同于 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 年的情况有所不同,但现在中止合并似乎相当可靠,所以我认为现在将其描述为“更容易且更不容易出错”是不公平的。
P
Pablo Olmos de Aguilera C.

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

git log ...@{u}

我相信这需要 git 1.7.x。 @{u} 表示法是上游分支的“简写”,因此它比 git log ...origin/master 更加通用。

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

git log ...@\{u\}

m
michael

添加到现有答案中,可以创建一个别名以在合并之前显示差异和/或日志。许多答案省略了在“预览”合并之前首先完成的 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,“合并” - 很酷的词! :) 我真的很喜欢你的回答,它显示了一个合并预览的用例,有些人可能会觉得有帮助。现在,如果您重新阅读该问题,然后我对您的答案的第一条评论,您可能会注意到我完全打算强调拉动(本质上只是一个提取然后合并)是您唯一的情况在预览或应用合并之前完全需要获取。并且 OP 只专门询问了合并部分,除了更新本地分支并对其远程对应部分进行更改之外,它还有许多用例。
N
Noufal Ibrahim

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

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

这些会有帮助吗?


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

没有以一种丢弃的方式实际执行合并(参见 Kasapo 的回答),似乎没有一种可靠的方式来看待这一点。

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

git log TARGET_BRANCH...SOURCE_BRANCH --cherry

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

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


G
G-Man

拉取请求 - 我已经使用了大部分已经提交的想法,但我也经常使用的一个是(特别是如果它来自另一个开发者)做一个拉取请求,它提供了一种方便的方法来审查合并中的所有更改,然后再进行地方。我知道那是 GitHub 而不是 git,但它确实很方便。


C
Chugaister

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


C
Community

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


A
Andronicus

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

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

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

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