本文介绍了git merge将优先级分配给较旧的分支的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几周前,我的搭档乔恩"(Jon)开设了一个新分支,以从事一项新功能.同时,团队的其余成员在许多新功能上进行了大量工作,我们创建了新分支并将其合并,并且始终将工作合并到(例如)分支更新(分支)中.但是"Jon"尚未完成,他从未从我们更新的工作中更新过他的分支.现在,与乔恩"合并的时刻到了.问题是,当我尝试与乔恩合并时,他的工作优先于我的工作.

A few weeks ago my partner "Jon" opened a new branch to work on a new feature. Meanwhile the rest of the team worked a lot in a bunch of new features, we created new branchs and merge them and always the work was merge in (lets say) branch-update branch. But "Jon" havent completed yet, and he never updated his branch from our updated work. Now the moment to merge with "Jon" has come. Problem is that when I try to merge with Jon his work has priority over mine.

我有 branch-update branch-jon ,如果HEAD指向 branch-update ,并且我说 git merge分支-jon 的结果是分支-乔恩比许多已经更新的文件具有优先权,乔恩从没在他的分支中碰过.如果HEAD指向 branch-jon ,并且我说 git merge branch-update ,结果仍然相同.

I have branch-update and branch-jon, if HEAD points to branch-update and I say git merge branch-jon the result is branch-jon has priority over a lot of files that are already updated, and jon never touched in his branch. if HEAD points to branch-jon and I say git merge branch-update the result still the same.

所以,我的问题是是否有一种方法可以通知git branch-update 优先于 branch-jon ,并且合并只会使我的jon更新工作吗?

So, my question is if there is a way to inform git that branch-update has priority over branch-jon, and the merge should only bring me jon updated work?

推荐答案

在合并中没有优先级"之类的东西.好吧,可能是 ,但是分配了它;您一会儿就会明白我的意思.

There is no such thing as "priority" in merges. Well, there can be, but you assign it; you'll see what I mean in a moment.

合并是关于合并的工作.但是,要合并工作,无论您是谁,无论他们是谁,都必须有一个共同的起点.由于Git完全是关于 commits 的内容-文件只是嵌入在commits中,因此,这个共同的出发点是 shared commit .

Merging is about combining work. To combine work, though, you and they, whoever they are, must share a common starting point. Since Git is all about commits—files are just embedded inside commits—this common starting point is a shared commit.

例如,尝试使用 git log --graph --decorate --online branch-update branch-jon .您将看到的可能非常复杂;我要画一些简单的东西.Git用最近的提交到顶部,下面的提交来绘制图表.出于空间原因,我倾向于水平绘制图形.

Try using git log --graph --decorate --online branch-update branch-jon, for instance. What you will see may be quite complicated; I'm going to draw something simple. Git draws the graph with more recent commits towards the top, and earlier commits below; for space reasons, I tend to draw my graphs horizontally.

请记住,每个提交都是所有文件的完整快照,并在时间上冻结(不可变),并包含其前任或 parent 提交的哈希ID.这意味着我们(或Git)可以从最近的提交开始(由某个分支名称标识),可以向后进行操作,一次提交一次:

Remember that each commit is a full snapshot of all files, frozen in time—immutable—and contains the hash ID of its predecessor or parent commit. This means that starting at the most recent commit, identified by some branch name, we—or Git—can work backwards, one commit at a time:

             I--J   <-- branch-update (HEAD)
            /
...--F--G--H
            \
             K--L   <-- branch-jon

在这个(高度简化,以至于不切实际的简单点)示例中,您和Jon自共同起点以来分别进行了两次提交.实际的共同起点是commit H ( H 实际上是一些丑陋的哈希ID, git log --oneline 将打印缩写).通过从您的最新提交 J 开始,并向后依次工作至 I H ,并从Jon的最新提交 L 然后向后依次到 K H ,Git将自动 找到这个最佳共享的常见提交.Git将此最佳共享提交称为合并操作的合并基础.(请注意,提交 G F 等也被共享;它们并不是最好的.)

In this (highly simplified, to the point of unrealistically simple) example, you and Jon have two commits each that you have made since the common starting point. The actual common starting point is commit H (H is really some big ugly hash ID, which git log --oneline will print abbreviated). By starting at your latest commit J and working backwards to I and then H, and starting at Jon's latest commit L and working backwards to K and then H, Git will automatically find this best-shared-common-commit. Git calls this best shared commit the merge base of the merge operation. (Note that commits G and F and so on are also shared; they're just not best.)

(Git可能将此图形绘制为:

(Git might draw this graph as:

* abcdef0 (HEAD -> branch-update) your commit subject
* c9f1233 your previous commit subject
| * 5bf3149 (branch-jon) his commit subject
| * 78983fc his previous commit subject
|/
* 371820d shared commit subject line
[snip]

尽管方向发生了变化,但这两张图表示的是同一张图.)

Despite the change in orientation, these two drawings represent the same graph.)

您的实际图形将更加混乱.合并基础在哪里可能不清楚.您可以让Git告诉您哪个提交是(或可能但不太可能是提交)合并基础:

Your actual graph will be far more tangled. It may not be clear where the merge base is. You can have Git tell you which commit is (or, possible but unlikely, commits are) the merge base:

git merge-base --all branch-update branch-jon

如果这会产生多个合并基数,则情况会稍微复杂一些,但是通常您只会看到一个提交哈希ID作为输出.

If this produces multiple merge bases, the situation is a little more complicated, but usually you'll just see one commit hash ID as the output.

在任何情况下,都已经找到了合并基础(就像在我的图形中那样叫它 H ),Git现在必须比较合并基础 H 中的快照,针对您的最新快照 J 找出您所做的更改.它还必须将 H 中的快照与其他最新快照进行比较,以查看Jon所做的更改.因此它运行两个 git diff 命令:

In any case, having located the merge base—let's just call it H as in my drawing—Git now has to compare the snapshot in H, the merge base, against your latest snapshot, J, to find out what you changed. It also has to compare the snapshot in H against the other latest snapshot, to see what Jon changed. So it runs two git diff commands:

  • git diff --find-renames Hash-of-H hash-of-J :您所做的更改
  • git diff --find-renames Hash-of-H hash-of-L :乔恩做了什么改变

现在,Git实际上合并了更改.首先从共同的起点从提交 H 中提取所有文件.对于这些文件,它将应用您的更改.它还适用于乔恩的更改.在某些情况下,应用很容易:例如,如果您更改了文件 F1 F2 ,而Jon没有触摸这些文件,则结果为您的 F1 您的 F2 .如果Jon触摸了 F3 而您没有触摸,则结果为他的 F3 . H 中的许多其他文件在 J L 中可能完全相同,因此您甚至无法确定Git是否正在使用H J L .但是对于一些文件,例如 F4 both 和,您乔恩做了一些更改.

Now Git actually combines the changes. It starts by extracting all of the files from commit H—from the common starting point. To those files, it applies your changes. It also applies Jon's changes. In some cases, applying is easy: for instance, if you changed files F1 and F2 and Jon didn't touch those files, the result is your F1 and your F2. If Jon touched F3 and you didn't, the result is his F3. Many other files in H are probably exactly the same in J and L, so you can't even tell whether Git is using H's, J's, or L's. But for a few files, such as F4, both you and Jon made some changes.

这是 git merge 真正必须努力的地方.其他所有情况, git merge 都只是从 H J L 中取出一些文件而逃脱了.对于这些文件,您都接触过,Git确实必须结合更改.

This is where git merge really has to work hard. All the other cases, git merge got away with just taking some file from H, J, or L. For these files—the ones that you both touched—Git really does have to combine the changes.

如果您更改了 F4 的第10至15行,则Git将您的更改为这些行.如果Jon将第20行更改为第25行,则Git将 his 更改为这些行.不需要 作为优先级:Git只需进行 更改.

If you changed lines 10 through 15 of F4, Git takes your changes to those lines. If Jon changed lines 20 through 25, Git takes his changes to those lines. There's no need for priority: Git just takes both changes.

如果您将第30行更改为第35行怎么办?好吧,如果您都对这些行进行了相同更改,则Git只会获取这些更改的一个副本,并将该一个副本应用于 H .

What if you both changed lines 30 through 35? Well, if you both made the same change to those lines, Git just takes one copy of those changes, applying that one copy to the file from H.

但是,如果你们俩都将第30行更改为第35行,并且您进行了不同更改,那么现在就出现了问题.这是不存在的优先级不存在的地方.默认情况下,Git仅声明合并冲突,并放弃完成合并.这让您一团糟:您的工作树中有一个文件,其中包含在冲突的一组更改周围的冲突标记.Git还会在索引中留下所有三个输入文件.修复Git机器,这是您的工作,就像人工操作Git机器的人一样.

But if both of you changed lines 30 through 35, and you made different changes, well, now there's a problem. This is where the priority that doesn't exist doesn't come in. By default, Git just declares a merge conflict and gives up on completing the merge. It leaves you with a mess: you have, in your work-tree, a file containing conflict markers around the conflicting set of changes. Git also leaves you with all three input files in the index. It becomes your job, as the human operating the Git machinery, to fix up the mess.

这也是可以选择的优先级"出现的地方.如果您使用标准的递归合并策略,则可以使用-X我们的 -X他们的参数(我将其称为 eXtended参数,尽管Git将其称为 strategy参数)告诉Git:如果发生冲突,请选择我的更改( -X我们的)或他的更改( -X他们的).

This is also where the "priority" that you can select comes in. If you are using the standard recursive merge strategy, you can use the -X ours or -X theirs arguments—which I call eXtended arguments, though Git calls them strategy arguments—to tell Git: In the case of a conflict, pick my changes (-X ours) or his changes (-X theirs).

大多数人最初想到 git merge 时会犯的错误是,认为只有两个输入并且正在运行:

The mistake most people make at first when thinking about git merge is thinking that there are only two inputs, and that running:

git diff branch-update branch-jon

告诉您将要发生的事情.那是完全错误的!每次合并有三个输入:当前( HEAD )提交及其文件,您提供的另一个提交( branch-jon ),和合并基础.Git从 commit图本身找到第三输入(在重要意义上实际上是第一输入).该图在这里非常重要.该图确定了合并基础,与两个分支技巧相比,合并基础确定了合并的结果.

tells you what's going to happen. That's completely wrong! There are three inputs to each merge: the current (HEAD) commit and its files, the other commit you supply (branch-jon), and the merge base. Git finds the third input—which in an important sense is really the first input—on its own, from the commit graph. The graph is all-important here. The graph determines the merge base, and the merge base, when compared to the two branch tips, determines the outcome of the merge.

合并过程本身(Git到达将要进入新合并的内容的路径)是对称的.哪个 git diff 首先运行并不重要.但是,当您说 -X我们的 -X他们的时,这破坏了对称性:发生冲突时,您选择一方或另一方为主导.

The merge process itself—the path by which Git arrives at the content that will go into the new merge—is symmetric. It doesn't matter which git diff gets run first. However, when you say -X ours or -X theirs, that breaks the symmetry: you're picking one side or the other to prevail when conflicts occur.

最后,当Git从合并的文件进行提交时,它也是不对称的.新提交的 first 父级基于 HEAD :附加了 HEAD 分支的那个分支,该分支的尖端提交是的第一父级新的合并提交.新提交的 second 父级是另一个提交.当然,新提交的哈希ID通过 HEAD 进入当前分支,因此,当我们获得新的合并提交 M 时, current 分支是获得它的分支:

In the end, when Git makes a commit from the merged files, that, too, is asymmetric. The first parent of the new commit is based on HEAD: whichever branch HEAD is attached-to, that branch's tip commit is the first parent of the new merge commit. The second parent of the new commit is the other commit. And of course, the new commit's hash ID goes through HEAD into the current branch, so that when we get new merge commit M, the current branch is the one that acquires it:

             I--J
            /    \
...--F--G--H      M   <-- branch-update (HEAD)
            \    /
             K--L   <-- branch-jon

请注意,此合并提交及其两个父级的存在会在以后的合并中更改图结构.现在,在 branch-update branch-jon 之间最好的共享通用提交是commit L :

Note that the existence of this merge commit, with its two parents, changes the graph structure in a future merge. Now the best shared common commit between branch-update and branch-jon is commit L:

             I--J
            /    \
...--F--G--H      M--N--O   <-- branch-update (HEAD)
            \    /
             K--L--------P   <-- branch-jon

如果您现在运行 git merge branch-jon ,Git会比较 L O 来找到我们所做的更改,然后L P 来查找它们的更改.

If you now run git merge branch-jon, Git will diff L vs O to find what we changed, and L vs P to find what they changed.

这篇关于git merge将优先级分配给较旧的分支的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-28 05:44