Git Merge Conflict:添加要在解决时提交的更改? [英] Git Merge Conflict: Add Changes to be committed when resolved?

查看:76
本文介绍了Git Merge Conflict:添加要在解决时提交的更改?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我经常遇到以下合并冲突问题,并已解决,但我想问一下我的解决方案是否正确.就个人而言,鉴于功能测试正在通过中,我看不到任何问题,但是对此有一个深入的了解将是很好的.

I frequently come across the following Merge Conflict issue and resolving it but I would like to ask if my solution is correct. Personally, I do not see any issues given that the functional tests are passing but it would be nice to have an insight on this one.

所以,假设我们有两个分支:

So, let's say we have got two branches:

  1. develop
  2. 功能

我要更改 feature 分支中的代码,然后创建PR以合并到 develop 中.但是, Github Bitbucket 的差异工具表明我们发生了合并冲突.编码中很常见的情况.

I am changing the code in feature branch and then creating a PR to merge into develop. However, Github's or Bitbucket's diff tool suggests that we have got a Merge Conflict; pretty common situation in coding.

然后我执行以下步骤:

  1. git checkout开发 git pull origin开发

git checkout功能,然后 git pull origin功能

`您有未合并的路径.(修复冲突并运行"git commit")

`You have unmerged paths. (fix conflicts and run "git commit")

要提交的更改:

modified:   app/BlablaFile.php
    modified:   app/Blabla2File.php
    renamed:    app/OldName.php -> app/NewName.php

然后:

Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   app/UnmergedFile.php

基本上是我为解决合并冲突而编辑的文件的列表.

which is basically a list of the files that I edited to resolve the merge conflict.

问题是我应该只 git添加app/UnmergedFile.php ,然后再 git commit -m"Updated app/UnmergedFile.php" 吗?还是我应该 git add 还要包含要提交的更改:部分中包含的文件?

Question is should I only git add app/UnmergedFile.php and then git commit -m "Updated app/UnmergedFile.php"? Or I should git add also the files that are included in the Changes to be committed: section?

我通常会做第一个,但是再想一想会很好.

I normally do the first one but it would be nice to have another thought.

推荐答案

TL; DR:您无需重新添加要提交的更改"中的文件.

TL;DR: You do not need to re-add files that are in "changes to be committed".

Git有一个叫做 index staging区域的东西,有时甚至称为 cache (如git diff --cached ).它的解释不是很好,部分是因为它很复杂.幸运的是,索引的 use 非常简单,除了合并期间的(alas).:-)

Git has a thing called, variously, the index or the staging area, or sometimes even the cache (as in git diff --cached). It's not very well explained, in part because it's complicated. Fortunately, the use of the index is pretty simple, except (alas) during merges. :-)

最好将索引中的内容描述为您将进行的下一次提交.这还有助于记住Git始终有一个当前提交,名为 HEAD,以及(在-bare 存储库中除外),工作树工作树,您可以在其中找到自己的准备查看,编译,编辑的文件,以及您对文件所做的任何其他操作.

What's in the index is best described as the next commit you will make. It also helps to remember that Git always has a current commit, named HEAD, and (except in --bare repositories), a work-tree or working tree, which is where you have your files ready for viewing, compiling, editing, and whatever else it is you do with your files.

最初,您的工作树,索引和 HEAD 会提交所有匹配项(首次克隆存储库时).您不能直接在索引中触摸文件,因此您需要在工作树中进行所有更改,甚至创建新文件.然后,要将修改后的文件放回索引中,请在路径上运行 git add ,以便Git将修改后的文件复制到索引中.要将新文件放入索引,您还可以在路径上运行 git add .

Initially, your work-tree, index, and HEAD commit all match (when you first clone a repository). You can't touch files directly within the index, so you make any changes—or even create new files—in the work-tree, where you do all your work. Then, to put a modified file back into the index, you run git add on the path, so that Git copies the modified file into the index. To put a new file into the index, you also run git add on the path.

如果由于某种原因使您兴奋不已并立即运行 git commit ,Git将读取您当前的索引并将其打包为新的提交.新提交将以现在处于索引状态的索引为索引中的每个文件作为其工作树快照.

If you were, for some reason, to get all excited and run git commit right now, Git would read your current index and package it up as a new commit. The new commit would have, as its work-tree snapshot, every file that is in the index now, in the state that it is now, in the index.

如果该状态与 HEAD 提交相匹配,则 git commit 只会说:呵呵?为什么现在尝试进行新的提交?"因此,大概到此为止您已经更改了索引中的某些内容. git status 将向您显示与 HEAD 提交 不同的索引中的内容:这些是要提交的更改".

If that state matches the HEAD commit, git commit just says: "Huhwha? Why you try to make new commit now?" So presumably you've changed something in the index by this point. git status will show you what's in the index that's different from the HEAD commit: these are "changes to be committed".

运行 git merge 有时会揭示有关索引的秘密.索引中的每个条目实际上都有四个插槽,它们均已编号.通常,您只会看到零插槽,该插槽是为普通"文件保留的,随时可以提交.

Running git merge sometimes reveals a secret about the index. Each entry in the index actually has four slots, which are numbered. Normally, you only ever see slot zero, which is reserved for "normal" files, ready to be committed.

合并旨在组合两套(或更多套,但让我们坚持两套)更改.例如,也许您和鲍勃开始使用相同的文件.然后,您对某些文件进行了一些更改,并 git add -ed并提交了源的新快照.同时,Bob对某些文件(甚至可能是相同的文件)以及 git add -ed和commit进行了一些更改,现在是时候结合您的更改和Bob的更改了.

Merging is intended to combine two (or sometimes more, but let's stick with two) sets of changes. For instance, perhaps you and Bob started with the same files. Then you made some changes to some files, and git add-ed and committed new snapshots of the source. Meanwhile Bob made some changes to some files—maybe the same files, even—and also git add-ed and committed, and now it's time to combine your changes and Bob's changes.

要执行合并(要以动词形式合并某些文件),Git首先会找到合并基础,即您和Bob同步的位置.然后Git运行两个 git diff :一个从该合并库到您的最新提交,另一个从同一合并库到 Bob 最新提交.这将显示您所做的更改"和鲍勃所做的更改".

To perform a merge—to merge-as-a-verb some file(s)—Git first finds the merge base, i.e., the point where you and Bob were in sync. Then Git runs two git diffs: one from that merge base to your latest commit, and one from that same merge base to Bob's latest commit. This shows "what you changed" and "what Bob changed".

Git会尽力合并这些更改(例如,在这种情况下,包括找出并重新命名文件,以及找出仅一个时该怎么做.您重命名了一些文件-但是大多数合并冲突都不包括文件重命名,除非您编写了许多Java代码...).但是有时候,Git不能独自做到这一点.在这种情况下,Git将合并工作交还给您,此时您可以在索引中看到所有 slots .

Git then does its best to combine those changes (including, as in this case, figuring out and following file renames, and figuring out what to do if only one of you renamed some file—but most merge conflicts don't include file renames, unless you write a lot of Java code...). Sometimes, though, Git can't do this on its own. In that particular case, Git puts the merge work back to you, and it's at this point that you see all the slots in the index.

索引插槽1是Git存储文件的 base 版本的位置.这是你们俩都从那里开始的普通版本.

Index slot 1 is where Git stores the base version of the file. That's the common version, from which you both started.

索引插槽2是文件的 HEAD -我们的版本.(有时也称为本地"版本.)

Index slot 2 is the HEAD or --ours version of the file. (It is also sometimes called the "local" version.)

索引插槽3是文件的另一个版本或-其(有时是远程")版本.

Index slot 3 is the other or --theirs (or sometimes "remote") version of the file.

这几乎就是所有内容:三个插槽包含三个版本,最后得到未合并的路径".您的工作树中的文件包含Git最初的合并工作,冲突标记以及-我们的-其版本的一些混搭.如果将 merge.conflictstyle 设置为 diff3 ,则Git还将包含文件的 base 版本中的部分,存储在索引插槽1中.现在由您来解决合并.

That's almost all there is to it: the three slots hold the three versions, and you end up with "unmerged paths". The file in your work-tree holds Git's initial effort to merge, along with conflict markers and some mash-up of the --ours and --theirs version. If you set merge.conflictstyle to diff3, Git will also include the parts from the base version of the file, stored in index slot 1. It's now up to you to resolve the merge.

找到正确的分辨率并更新文件的工作树版本后,必须 git add 路径.这会将工作树版本存储到索引插槽零中,从而清除插槽1-3中的三个条目.由于插槽0拥有正常的,即将提交的版本,因此文件现在可以提交了.

Once you've figured out the correct resolution, and updated the work-tree version of the file, you must git add the path. This stores the work-tree version into index slot zero, wiping out the three entries in slots 1-3. Since slot zero holds the normal, to-be-committed version, the file is now ready to commit.

对于根本没有更改的文件,只是您其中之一更改了某些内容,其中Git认为它正确地结合了您的更改和Bob的更改,那些文件已经在工作树索引和(索引的插槽零)中进行了更新.如果结果与当前的 HEAD 提交不同,则 git status 会将文件显示为要提交的更改".

For files where there were no changes at all, or just one of you changed something, or where Git thinks it correctly combined your changes and Bob's changes, those files are already updated in both work-tree and (slot zero of) index. If the result differs from the current HEAD commit, git status shows the file as "changes to be committed".

我在上面说过,这几乎是全部了.关于索引槽,需要记住的最后几件事是:

I said above that this is almost all there is to it. The last few things to remember about the index slots are:

  • 某些插槽可能为空.假设您 Bob都添加了一个文件.在这种情况下,您将获得添加/添加冲突".该文件的哪个版本是通用基本版本?当然没有:你们都添加了 new 文件.因此,在这种情况下,基本插槽(插槽1)为空.

  • Some slots might be empty. Suppose both you and Bob added a file. In this case, you'll get an "add/add conflict". What version of the file is the common base version? There is none, of course: you both added a new file. So in this case, the base slot—slot 1—is empty.

如果删除文件而Bob更改了文件,也会发生同样的情况.在这种情况下,-我们的插槽(插槽2)为空,而插槽1和3保留基本版本和Bob的版本.由您决定是保留Bob的版本,删除文件还是使用第三个变体,但再次请注意,三个插槽中的两个仅被填充.

The same happens if you delete a file and Bob changes it. In this case, the --ours slot, slot 2, is empty, while slots 1 and 3 hold the base version and Bob's version. It's up to you to decide whether to keep Bob's version, keep the file removed, or use yet a third variant, but once again only two of the three slots are filled.

如果您中的一个或两个都重命名文件,则三个插槽中的文件版本可能来自先前提交中具有不同名称的文件.例如,您的输出显示:

If one or both of you renames a file, the file versions in the three slots may come from files that had different names in earlier commits. For instance, your output shows:

    renamed:    app/OldName.php -> app/NewName.php

这里没有冲突,但是如果存在冲突,则 app/NewName.php 的插槽中的至少一个将由 app/OldName的某些其他提交版本填充.php .

There was no conflict here, but if there had been, at least one of the slots for app/NewName.php would be filled from some other commit's version of app/OldName.php.

当您查看旧版本时,这主要很重要.如果在单独的克隆或工作树中检出了尚未重命名文件的提交之一,或者是否使用了 git show< commit>:app/OldName.php 查看文件而无需检出文件-无论旧名称为何,都必须使用 old 名称.但是,如果您使用 git checkout --ours git checkout --theirs 将这两个版本之一仅提取到工作树中,则必须使用新的名称,因为索引现在使用新名称存储了文件.

This mainly matters when you go to look at the old version. If, in a separate clone or work-tree, you check out one of the commits where the file is not yet renamed—or if you use git show <commit>:app/OldName.php to view the file without checking it out—you must use the old name wherever it has the old name. But if you use git checkout --ours or git checkout --theirs to extract just one of these two versions into the work-tree, you must use the new name, because the index now has the file stored under the new name.

如果您要做,请分别使用 git checkout --ours git checkout --theirs 来获取您或Bob的版本的文件,这不能解析文件,但是Clobber Git会尝试将它们合并到工作树中.如果要恢复Git合并它们的尝试,请使用 git checkout -m .请注意,所有这些都覆盖了文件的工作树版本,而只剩下三个未解决的索引槽.

If you do use git checkout --ours or git checkout --theirs to get your or, respectively, Bob's version of a file, this does not resolve the file, but does clobber Git's attempt to merge them in the work-tree. If you want to restore Git's attempt to merge them, use git checkout -m. Note that all of these overwrite the work-tree version of the file, while leaving the three unresolved index slots alone.

但是,如果您 git checkout< commit-id>-< path> 从某些特定的提交中获取文件的旧版本,该文件会覆盖索引:它将文件的提交版本复制到索引插槽零,这很麻烦插槽1-3项.该文件现在看来已解析!同样,您可以使用 git checkout -m 恢复未解决的状态.(当然,这会覆盖工作树版本.)

Weirdly, though, if you git checkout <commit-id> -- <path> to get an old version of a file out of some specific commit, that overwrites the index: it copies the commit's version of the file to index slot zero, clobbering the slot 1-3 entries. The file now appears resolved! Again, you can restore the unresolved state with git checkout -m. (Of course that overwrites the work-tree version.)

类似地,如果在尚未完成 的情况下错误地使用 git add 解析了文件,则可以进行 git checkout -m 来解决它,但是当然会覆盖工作树版本.如果您基本上已完成解析,则最好也完成解析并重新 git add 结果.这将零插槽索引条目替换为从工作树中新复制的版本:文件保持解析状态,但准备下一次提交的版本将更改为最新的 git add 版本./p>

Similarly, if you mistakenly resolve the file with git add when it's not quite done yet, you can git checkout -m to unresolve it—but of course, that overwrites the work-tree version. If you're mostly done resolving, you might as well finish resolving and re-git add the result. This replaces the slot-zero index entry with a version freshly copied from the work-tree: the file stays resolved, but the version ready for the next commit changes to the latest git add-ed version.

这篇关于Git Merge Conflict:添加要在解决时提交的更改?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆