问题描述
在您只是想用另一个文件(尤其是二进制文件)覆盖的情况下,我在Stack Overflow和其他地方找到了许多有关使用OURS/THEIRS动态程序解决冲突的指令.但是,在我发现的几乎每个示例中,它始终被应用于所有冲突,而我只想将其应用于单个冲突文件.
I've found many instructions on Stack Overflow and elsewhere for resolving conflicts using the OURS/THEIRS dynamic, in cases where you simply want to overwrite one file with another (particularly binary files). However in almost every example I find, it's always been applied en masse to all conflicts, whereas I only want to apply it to a single conflicted file.
我发现的一种可能的解决方案是使用git mergetool命令.但是,mergetool给我的问题是,我选择选择左"或选择右",但没有任何反应.
One supposed solution I found is to use the git mergetool command. However the mergetool is giving me issues, where I select "choose left" or "choose right" and nothing happens.
尽管不管使用了mergetool,我还是想知道是否有一种方法可以从命令行执行此操作.我敢肯定,如果有人让我知道该命令,或者以其他方式将我链接到我一定找不到的SO问题,我将不胜感激.
Regardless of mergetool though, I'd like to know anyway if there is a way to do this from the command line. I'm sure there is, and if anyone would let me know the command, or otherwise link me to the SO question I must not be finding, I'd appreciate it greatly.
我也尝试过使用...
I've also tried using...
git checkout-他们的PATH/TO/CONFLICTED/FILE
git checkout --theirs PATH/TO/CONFLICTED/FILE
但是当我输入'git status'时,它仍然显示文件冲突.
But then when I enter 'git status', it still shows the file as conflicted.
非常感谢您抽出宝贵的时间.
Thank you so much for your time.
推荐答案
TL; DR
除非您使用其他方法提取我们的"或他们的"版本,否则您将需要最终决议git add
.
每个合并工具都独立于Git(Git只是运行它们并让他们做事),因此对于该问题的特定子部分,您必须查阅合并工具本身.
Each merge tool is independent of Git (Git just runs them and lets them do their things) so for that particular sub-part of this question, you must consult the merge tool itself.
对于git checkout --ours
或git checkout --theirs
,好吧,这就是Git所说的 index 显示其全部复杂性的地方.请记住,索引实际上是一种神秘的索引,也称为暂存区,有时也称为 cache ,它实际上是您和Git建立 next的地方提交.
As for the git checkout --ours
or git checkout --theirs
, well, this is where what Git calls the index shows its full bit of complexity. Remember that the index, which is otherwise kind of mysterious and is also called the staging area and sometimes the cache, is essentially where you and Git build up the next commit you will make.
运行时:
git merge <commit-or-branch-specifier>
Git发现三个提交:
- 一个是您的当前提交,它是您在任何给定时间一直在使用的提交,因此这并不是很特殊,只是您可以使用名称
HEAD
来引用它.或单个字符@
(例如,git rev-parse HEAD
或git rev-parse @
以获得其哈希ID). - 一个是您刚刚命名的提交.如果运行
git merge otherbranch
,则可以运行git rev-parse otherbranch
来查看其提交哈希ID现在是什么. (分支名称具有 moving:的属性,也就是说,当前由分支名称标识的提交不一定是昨天或明天由该名称标识的提交.分支名称的此动议是如何当然,如果您运行git merge a123456
,则另一个提交(用于--theirs
的提交)是哈希IDa123456
. - 最后一次提交是合并基础,Git会自动为您找到.它通过使用您的提交和另一个提交中的父级链接来查找此提交,以通过两个分支向后工作,直到找到两个分支首先重新组合在一起的合适点.
- One is your current commit, which is the one you're always working with at any given time, so that's not really special, except that you can refer to it by the name
HEAD
or the single character@
(e.g.,git rev-parse HEAD
orgit rev-parse @
to get its hash ID). - One is the commit you just named. If you ran
git merge otherbranch
, you can rungit rev-parse otherbranch
to see what its commit hash ID is right now. (Branch names have the property of moving: that is, the commit identified by a branch name right now is not necessarily as the commit identified by that name yesterday, or tomorrow. This motion of branch names is how branches grow.) Of course if you rangit merge a123456
, the other commit, the one for--theirs
, is hash IDa123456
. - The last commit is the merge base, which Git finds for you automatically. It finds this commit by using the parent linkages from your commit and the other commit, to work backwards through both branches until it finds the appropriate point where the two branches first come back together.
实际上已经找到了三个提交,Git运行了:
Having found the three commits, Git runs, in effect:
git diff --find-renames <merge-base> <ours> # see what we changed
git diff --find-renames <merge-base> <theirs> # see what they changed
合并过程(实际上是作为合并动词的合并)包括查找这三个提交,进行比较以及组合更改.当两组更改影响同一行时,您将发生合并冲突.
The merge process—to merge as a verb, as it were—consists of finding these three commits, doing the diff, and combining the changes. You get a merge conflict when the two sets of changes affect the same lines.
在没有合并冲突的文件中,Git将结果放入您的工作树(作为普通文件)和索引(作为文件的特殊Git形式,准备提交)中.因此,对于没有冲突的文件,通常不需要执行其他任何操作.
In a file where there are no merge conflicts, Git puts the result into both your work-tree (as an ordinary file) and the index (as the special Git-form of the file, ready to be committed). So for unconflicted files, there is generally nothing else you need to do.
但是,当发生合并冲突时,Git会做两件不寻常的事情:首先,它将合并冲突的版本写入工作树,以便您可以将其编辑为纯文件.其次,它将写入文件的索引,而不是文件的一个版本,而是写入所有的三个 版本:合并基本版本,我们的"版本和它们的"版本
When there's a merge conflict, though, Git does two unusual things: first, it writes the merge-conflicted version into the work-tree, so that you can edit it as a plain file. Second, it writes into the index, not one version of the file, but all three: the merge base version, the "ours" version, and the "theirs" version.
Git将这些额外版本称为更高阶段.阶段号是合并的基础,没有--base
选项可以访问它,但是您可以使用git show :1:path
进行查看.第二阶段是我们的"版本:存在--ours
,但您也可以运行git show :2:path
进行查看.阶段3是他们的"版本,可通过git show :3:path
获得.这三个阶段替换了正常的零阶段输入,现在已经消失了.
Git calls these extra versions higher stages. Stage number is the merge base, and there's no --base
option to access it, but you can use git show :1:path
to see it. Stage number two is the "ours" version: there's --ours
but you can also run git show :2:path
to see it. Stage number 3 is the "theirs" version, available through git show :3:path
. These three stages replace the normal stage-zero entry, which is now missing.
实际上,当您运行git mergetool
时,要做的是在索引中找到三个版本,将它们提取到常规(非Git标准化)文件中,然后对这三个文件运行实际的合并工具.假定合并工具执行正确的事情"(无论结果如何),将三个文件合并为一个合并的文件,然后git mergetool
可以对结果运行git add
.
In fact, when you run git mergetool
, what that does is find the three versions in the index, extract them into regular (non-Git-ified) files, and run the actual merge tool on those three files. The merge tool is assumed to Do The Right Thing (whatever that turns out to be) to combine the three files into one merged file, after which git mergetool
can run git add
on the result.
但是,从命令行(这就是我进行合并的方式),您可以编辑带有冲突标记的工作树文件,并找出正确的结果.写出git add
生成的文件,对您来说很好,因为git add
注意到该文件以三阶段版本的形式存在,并删除了这三个版本,而是写入了阶段号零.
From the command line, though—which is how I do my merges—you can just edit the work-tree file, with its conflict markers, and figure out what the right result is. Write that out, git add
the resulting file, and you're good, because git add
notices that the file exists in the three-staged-versions form and erases those three versions, writing instead into stage number zero.
一旦阶段为零(不再是阶段1-3),该文件即被视为已解决.
Once there's a stage zero (and no longer stages 1-3), the file is considered resolved.
现在,git checkout --ours -- path
只是告诉Git:从索引中取出第二阶段的版本,并将其放入工作树中.带有--theirs
的版本告诉Git进行该阶段. -3版本代替.在这两种情况下,具有三个阶段版本的索引都将保留下来.仅 从索引中提取到工作树. (这里的--
是为了防止 path
部分是名为--theirs
的文件.如果文件名与选项不相似,则不需要--
.一直使用--
是一种好习惯,但大多数人不习惯.)
Now, git checkout --ours -- path
just tells Git: Take the stage-2 version out of the index and put it into the work-tree. The version with --theirs
tells Git to take the stage-3 version instead. In both cases, the index, with its three staged versions, is left alone. This only extracts from the index, to the work-tree. (The --
here is just in case the path
part is, say, a file named --theirs
. If the file name doesn't resemble an option, you don't need the --
. It's kind of a good habit to use the --
all the time, but most people don't.)
由于索引仍然具有所有三个暂存版本,因此该文件尚未解析.运行git add
将获取工作树文件,并将其放入插槽0中,清除掉1到3条目,现在文件已解析.
Since the index still has all three staged versions, the file is not yet resolved. Running git add
takes the work-tree file and puts it in slot zero, wiping out the 1-through-3 entries, and now the file is resolved.
奇怪的是,运行git checkout HEAD -- path
或git checkout otherbranch -- path
会使文件解析.这是Git的产物,它允许实现指示接口:在内部,当您使用git checkout name -- path
时,Git必须首先在给定的 name
中找到文件的Git形式(提交哈希或HEAD
或 otherbranch
之类的名称).然后,它必须复制 Git从到索引...,并且此复制会擦除插槽1-3的条目,并写入正常的插槽零条目.最后,Git然后从索引条目0提取(Git-form)文件到工作树.
Curiously, running git checkout HEAD -- path
or git checkout otherbranch -- path
causes the file to become resolved. This is an artifact of Git letting the implementation dictate the interface: internally, when you use git checkout name -- path
, Git has to first locate the Git form of the file in the given name
(a commit hash or a name like HEAD
or otherbranch
). Then it has to copy that Git form into the index ... and this copying wipes out the slot 1-3 entries, writing into the normal slot-zero entry. Last, Git then extracts the (Git-form) file from index entry zero to the work-tree.
首先写索引,然后从索引提取到工作树"的副作用是,如果文件处于冲突状态(处于1-3阶段处于活动状态),则不再冲突!因此:
The side effect of this "write to index first, then extract from index to work-tree" is that if the file was in conflicted state—had stages 1-3 active—it's no longer conflicted! Hence:
git checkout --ours -- file
不会解析文件(因为它是从索引插槽2中提取的),但是:
doesn't resolve the file (because it extracts from index slot 2), but:
git checkout HEAD -- file
做解析文件(因为它是从当前提交中提取的,所以将其移到索引插槽0,擦除了1-3; 然后从插槽0条目中提取了文件刚刚写过.)
does resolve the file (because it extracts from the current commit, going to index slot 0, wiping out 1-3; then extracts from the slot 0 entry it just wrote).
这篇关于可以使用我们的/他们的解决单个文件上的Git冲突吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!