简体   繁体   English

Git:自上次合并冲突以来,查看其分支上的更改

[英]Git: see changes on their branch since last merge on merge conflict

I thought that my scenario should be fairly common, and there must be a simpler way of doing what I do. 我认为我的情况应该相当普遍,并且必须有一种更简单的方式来做我的工作。 Suppose there are two branches, current and next , for two lines of development. 假设有两个分支, currentnext ,用于两条开发线。 next at this stage receives all changes from the current branch. 此阶段的next接收current分支的所有更改。 Being maintainer of the next branch I am syncing the changes (as necessary for alpha releases) like this: 作为next分支的维护者,我正在像这样同步更改(对于Alpha版本是必需的):

$ git co origin/next -b next
$ git merge origin/current

Some files changed their format on the next , and every change to these few files made since the last sync-merge results in a conflict. 某些文件在next上更改了格式,而自上次同步合并以来对这几个文件所做的每次更改都会导致冲突。 To resolve this conflict, I need to see the changes on the current branch since the previous merge. 为了解决此冲突,自上次合并以来,我需要查看current分支上的更改。 Usually many files have changed, but only 1 or 2 files like those I mentioned are conflicting. 通常,许多文件已更改,但只有1或2个文件(如我提到的文件)有冲突。

Example

Suppose that the file baz.dat on the current branch contains words in square brackets, like 假设current分支上的文件baz.dat包含方括号中的单词,例如

[real]
[programmers]
[use]
[pascal]

On the next branch, the syntax change demands that the words be surrounded with colons instead next分支上,语法更改要求单词以冒号代替

:real:
:programmers:
:use:
:pascal:

A change on the current branch has added a line to the file: current分支上的更改已在文件中添加一行:

[real]
[programmers]
[don't]
[use]
[pascal]

Every time a merge conflict results in the following diff merge marks: 每次合并冲突都会导致以下差异合并标记:

<<<<<<< ours
:real:
:programmers:
:use:
:pascal:
=======
[real]
[programmers]
[don't]
[use]
[pascal]
>>>>>>>> theirs

Whole file content deleted and replaced, because it, in a sense, is. 整个文件内容被删除和替换,因为从某种意义上说是这样。

Similarly, just git diff shows all incoming, "their" lines as deleted and "our" lines as added: 同样,仅git diff显示所有传入的“他们”行已删除,而“我们的”行已添加:

$ git diff
<usual unified diff preamble>
+  :real:
... more lines with "+ " (our new) or " -" (their deleted) mark, 
 - [pascal]

What I am looking for 我在寻找什么

A way to see what changed on the current ("their") branch since I last merged, so I can manually incorporate the change into the next ("our") branch 查看自上次合并以来current (“其”)分支上发生了什么更改的方法,因此我可以手动将更改合并到next (“我们的”)分支中

$ git diff --magically-from-merge-point --theirs
<usual unified diff preamble>
+ [don't]

In other words, I want to see in this example case that only one line was added, so I can insert it in the new format as well. 换句话说,我想在本例中看到只添加了一行,因此也可以将其插入新格式。

(My real case is a change in a domain-specific language, but it essentially very similar to this trivial example). (我的真实情况是特定领域语言的更改,但本质上与该简单示例非常相似)。

Current solution 当前解决方案

What I am resorting to do is a rather unwieldy series of commands: 我要采取的措施是一系列繁琐的命令:

$ git status 
. . . .
      both modified:   foo/bar/baz.dat <== copy/paste every conflict filename
$ git diff `git merge-base HEAD origin/current`..origin/current -- foo/bar/baz.dat

This shows what I want, but rather complex, and I construct and type it every time. 这显示了我想要的内容,但相当复杂,我每次都构造并键入它。 It is easy enough to script in bash, but before I do that I want to ask is there a simpler way to see the conflicting changes from merge base? 用bash编写脚本很容易,但是在我这样做之前,我想问一问,是否有一种更简单的方法来查看来自合并基础的冲突更改? I. e.

(next)$ git merge origin/current
. . . 
CONFLICT (content): foo/bar/baz.dat
(next|MERGING)$ git diff --magic-switch

and diff would show changes only for conflicting files as a delta between the merge base and the point of merge (which I would, in the ideal case, further restrict with eg --magic-switch --theirs ) 和diff仅将发生冲突的文件的更改显示为合并基础和合并点之间的增量(在理想情况下,我会用--magic-switch --theirs进一步限制)

Does such a magic switch exist? 是否存在这样的魔术开关? Looks like I am missing something obvious! 看来我缺少明显的东西!

git mergetool will open the conflicting files, one by one, in your diff editor of choice (meld, vimdiff, kdiff3, winmerge ...), as a 3 way merge between the 3 versions : git mergetool将在您选择的差异编辑器(meld,vimdiff,kdiff3,winmerge ...)中依次打开冲突文件,这是3个版本之间的3种合并方式:

  • local : version in the current branch (in your case : next 's version) local :当前分支中的版本(在您的情况下: next的版本)
  • base : version in the merge-base commit base :合并基础提交中的版本
  • remote : version in the merged branch (in your case : origin/current 's version) remote :合并分支中的版本(在您的情况下: origin/current的版本)

If you edit + save the central file, git will mark this conflict as solved, an stage what you saved in the index. 如果编辑+保存中央文件,则git会将此冲突标记为已解决,这是您保存在索引中的阶段。


If your merge halted due to conflict, git stores a ref to the merged commit in .git/MERGE_HEAD . 如果您的合并由于冲突而中止,则git将对合并提交的引用存储在.git/MERGE_HEAD This means that you can use the string "MERGE_HEAD" as a valid reference in git commands : 这意味着您可以在git命令中使用字符串"MERGE_HEAD"作为有效引用:

git log -1 MERGE_HEAD            # view last commit on the merged branch
git merge-base MERGE_HEAD HEAD   # no need for the name of the branch

You can then build a simpler alias : 然后,您可以构建一个更简单的别名:

theirs = 'git diff $(git merge-base MERGE_HEAD HEAD) MERGE_HEAD'
# usage :
git theirs                  # complete diff between 'base' and 'theirs'
git theirs -w -- this/file  # you can add any option you would pass to 'git diff'

Ah, with the example we can get somewhere. 啊,有了这个例子,我们可以到达某个地方。

This is not built in to Git because it's a very hard problem in general. 这不是Git内置的,因为通常这是一个非常棘手的问题。 But if we constrain it somewhat, we can write a script or tool or procedure to deal with it (and that part, it turns out, is built into Git! ... well, sort of). 但是,如果我们对其进行某种程度的约束,则可以编写脚本或工具或过程来对其进行处理(事实证明, 部分内置在Git!中……不错)。 Let's see if we can describe the constraints: 让我们看看是否可以描述约束:

  • This is a standard three-way merge, with a standard modify conflict, so there is a base version (stage 1), a local/HEAD/ --ours version (stage 2), and a remote/other/ --theirs version (stage 3). 这是一个标准的三路合并,用标准修改冲突,所以一个基本版本(阶段1),本地/ HEAD / --ours版本(阶段2),以及远程/其它/ --theirs版本(第3阶段)。

  • One "side" of the merge touches every line, but in a repeating and identifiable pattern, which we could back out, perhaps temporarily. 合并的“一侧”触及每一行,但以一种可重复的,可识别的模式,我们可以暂时退出。 (Let's give this change a name: let's call it a "systematic delta" or SD for short, and +SD means add or keep this delta, while -SD means undo / remove it. The SD may be an irreversible change, ie, -SD might not undo it perfectly; if so, we may still be able to handle it automatically.) It may or may not also have some additional changes, vs the base. (我们给这个更改起个名字:我们简称为“系统增量”或SD,+ SD表示添加或保留此增量,而-SD表示撤消/删除它。SD可能是不可逆的更改,即, -SD可能不会完全取消它,如果是这样,我们仍然可以自动处理它),它可能会或可能不会也有一些额外的改变,VS基地。

  • The other "side" of the merge only touches a few lines, or even no lines, and lacks the repeating-and-identifiable pattern change, which we could add to it, perhaps temporarily. 合并的另一“边”仅涉及几行,甚至不涉及任何行, 并且缺少可重复的和可识别的模式更改,我们可以暂时将其添加到其中。

We have a few additional questions and decisions to consider here, perhaps on an ad-hoc case-by-case basis or perhaps systematically. 在这里,我们还有一些其他问题和决定需要考虑,可能是逐案或系统地考虑。 They will affect how we write our script, tool, or procedure. 它们将影响我们编写脚本,工具或过程的方式。 These are: 这些是:

  • Is the SD actually reversible? SD实际上是可逆的吗? That is, once we discover the SD, does base + SD - SD reproduce the original base? 也就是说,一旦发现SD,基准+ SD-SD是否会重现原始基准?
  • Do we want the SD in the result? 我们是否需要结果SD?
  • Can we detect the presence of the SD? 我们可以检测到SD的存在吗? (We may not need to, but we will see that it's convenient if we can.) (我们可能不需要,但是如果可以的话,我们会发现这样做很方便。)

If the SD is reversible, we are in good shape because we can get any result we like. 如果SD 可逆的,那么我们就处于良好状态,因为我们可以获得想要的任何结果。 If not, we'll have to apply the SD to whichever side lacks it: this is OK if and only if we want the SD in the result. 如果没有,我们将必须将SD应用于缺少它的任何一方:当且仅当我们希望将SD包含在结果中时,这才可以。

Let's assume for the moment that we want +SD in the result. 让我们暂时假设我们想要+ SD。 In this case, we're in great shape: let's just call the process of applying the SD "normalizing" the file. 在这种情况下,我们处于良好状态:让我们仅将应用SD的过程称为“规范化”文件。 Or, if we want -SD in the result, and the SD is reversible, let's call doing -SD "normalizing". 或者,如果我们想要-SD结果, 并且 SD 可逆的,那么我们称做-SD为“规范化”。 Furthermore, if we can tell whether a file has SD applied, we can just write a "normalizer filter" and run everything through that filter. 此外,如果我们可以判断文件是否已应用SD,则只需编写“规范化过滤器”并通过该过滤器运行所有内容。

This is what is built in to Git: it has "clean" and "smudge" filters, as described in the gitattributes documentation . 这就是Git的内置功能:它具有gitattributes文档中所述的“干净”和“涂抹”过滤器。 Furthermore, we can instruct git merge to run the two filters (both of them—but we can make them both be "normalize", or leave one unset, for our particular purpose here) on each file before doing the merge. 此外,在git merge ,我们可以指示git merge在每个文件上运行两个过滤器(两者-但我们可以使它们都被“规范化”,或出于我们的特定目的而未设置它们)。 Since "normalizing" gives us the final form we want, it makes Git do the merge we want done. 由于“规范化”为我们提供了所需的最终形式,因此它使Git可以完成所需的合并。

If the SD is not reversible, we need to be more clever, but as long as we want +SD in the result, we are still OK. 如果SD是不可逆的,我们需要变得更聪明,但是只要我们想要+ SD,我们仍然可以。 Instead of using the merge.renormalize setting described in gitattributes , we can write our own merge driver. 而不是使用merge.renormalize中所描述的设置gitattributes ,我们可以写我们自己的合并驱动程序。 This is also documented (further down) in the same manual. 同一手册中也对此进行了记录(进一步介绍)。 I won't go into detail here since the clean/smudge filter method is easier and likely to work for your case, but the essence is that we extract the three stages, apply +SD to whichever ones need it (selecting "files that need it" by test or by prior knowledge), and then use git-merge-file to achieve the desired merge on the three (now all +SD) inputs. 由于清理/污迹过滤器方法更容易并且可能适合您的情况,因此在此不做详细介绍,但是本质是我们提取了三个阶段,将+ SD应用于需要的任何阶段(选择“需要”的文件它”(通过测试或通过先验知识),然后使用git-merge-file在三个(现在为所有+ SD)输入上实现所需的合并。

Note that the .gitattributes file that is present in the work-tree at the time you run git merge , plus any configuration items you select in .gitconfig or with a -c command line option to git , control the filtering and renormalization at the time you run git merge . 请注意,运行git merge时工作树中存在的.gitattributes文件,以及您在.gitconfig选择的任何配置项,或者使用-c命令行选项进行git ,同时控制过滤和重新规范化您运行git merge This .gitattributes file need not even be checked-in anywhere. .gitattributes文件甚至无需在任何位置检入。 This means you can have different .gitattributes files in effect at different times, either by making it an ordinary tracked file and switching commits and/or branches (so that Git updates it for you), or just by updating it manually as needed. 这意味着您可以在不同的时间使用不同的 .gitattributes文件,方法是将其.gitattributes普通的跟踪文件并切换提交和/或分支(以便Git为您更新),或者仅根据需要进行手动更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM