这听起来可能是一个太基本的问题,但我一直在寻找答案,现在我比以前更困惑了。
当我的分支合并到我的另一个分支时,“我们的”和“他们的”在git中是什么意思?
两个分支都是“我们的”。
在合并冲突中,“我们的”总是显示两个版本的上部吗?
“我们的”是否总是指合并开始时HEAD所指向的分支?如果是这样,那么为什么不使用一个明确的所有格,如“当前分支的”,而不是使用一个所有格代词,如“我们的”,这是指模棱两可的(因为两个分支在技术上都是我们的)?
或者只是使用分支名称(而不是说“我们的”,而是说“本地主人的”或类似的)?
最让我困惑的部分是,如果我在一个特定分支的.gitattributes文件中指定。让我们说在测试分支中,我有以下.gitattributes文件:
config.xml merge=ours
现在我签出并点HEAD到master,然后在测试中合并。因为master是我们的,test的.gitattributes没有签出,它会有影响吗?如果真的有效果,既然师父现在是“我们的”了,那又会怎样呢?
从git checkout的用法来看:
-2, --ours checkout our version for unmerged files
-3, --theirs checkout their version for unmerged files
-m, --merge perform a 3-way merge with the new branch
在解决合并冲突时,你可以执行git checkout—他们的some_file和git checkout—我们的some_file来分别将文件重置为当前版本和传入版本。
如果你已经完成了git checkout——我们的some_file或git checkout——他们的some_file,并想要将文件重置为文件的3向合并版本,你可以执行git checkout——merge some_file。
我怀疑你在这里感到困惑,因为它从根本上令人困惑。更糟糕的是,当你在做rebase时,我们/他们的所有东西都转换了角色(变成了倒退)。
最终,在git合并过程中,“ours”分支指的是你要合并到的分支:
git checkout merge-into-ours
“their”分支指的是你要合并的(单个)分支:
git merge from-theirs
在这里,“ours”和“their”是有意义的,因为即使“their”可能是你的,“their”也不是你在运行git merge时使用的那个。
虽然使用实际的分支名称可能很酷,但在更复杂的情况下就不行了。例如,你可以这样做:
git checkout ours
git merge 1234567
通过原始commit-ID进行合并。更糟糕的是,你甚至可以这样做:
git checkout 7777777 # detach HEAD
git merge 1234567 # do a test merge
在这种情况下,不涉及分支名称!
我认为这在这里没有什么帮助,但实际上,在gitrevisions语法中,您可以在冲突合并期间通过数字引用索引中的单个路径
git show :1:README
git show :2:README
git show :3:README
阶段#1是文件的共同祖先,阶段#2是目标分支版本,阶段#3是您要合并的版本。
“我们的”和“他们的”概念在改基过程中交换的原因是改基工作是通过做一系列的筛选,进入一个匿名分支(分离的HEAD模式)。目标分支是匿名分支,而merge-from分支是你的原始(预重基)分支:所以“——our”意味着匿名的一个重基正在构建,而“——their”意味着“我们的分支正在重基”。
至于gitattributes条目:它可能会产生影响:“ours”实际上在内部意味着“使用阶段#2”。但正如你所指出的,当时它还没有到位,所以它应该不会在这里产生影响……除非在开始之前将它复制到工作树中。
另外,顺便说一下,这适用于我们和他们的所有使用,但有些是在整个文件级别(-s我们的合并策略;git签出——在合并冲突时是我们的),有些是逐块的(在-s递归合并时是-X我们的或-X他们的)。这可能无助于解决任何困惑。
不过,我从来没有想过一个更好的名字。并且:参见VonC对另一个问题的回答,其中git mergetool为这些引入了更多的名称,称它们为“本地”和“远程”!
Git中的“our”指的是原始的工作分支,它在Git历史中具有权威/规范的部分。
“their”指的是保存工作以便重基于的版本(要在当前分支上重放的更改)。
这可能会被那些没有意识到做重基(例如git重基)实际上是在暂停你的工作(这是他们的),以便重放到我们的规范/主历史上,因为我们将我们的更改作为第三方工作重基。
Git -checkout的文档在Git >=2.5.1中根据f303016提交得到了进一步的澄清:
--ours
--theirs
When checking out paths from the index, check out stage #2
('ours') or #3 ('theirs') for unmerged paths.
Note that during git rebase and git pull --rebase, 'ours' and 'theirs' may appear swapped; --ours gives the version from the branch the changes are rebased onto, while --theirs gives the version from the branch that holds your work that is being rebased.
This is because rebase is used in a workflow that treats the history at the remote as the shared canonical one, and treats the work done on the branch you are rebasing as the third-party work to be integrated, and you are temporarily assuming the role of the keeper of the canonical history during the rebase. As the keeper of the canonical history, you need to view the history from the remote as ours (i.e. "our shared canonical history"), while what you did on your side branch as theirs (i.e. "one contributor's work on top of it").
对于git-merge,它的解释如下:
ours
This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side.
This should not be confused with the ours merge strategy, which does not even look at what the other tree contains at all. It discards everything the other tree did, declaring our history contains all that happened in it.
theirs
This is the opposite of ours.
此外,这里解释了如何使用它们:
合并机制(git merge和git pull命令)允许使用-s选项选择后端合并策略。一些策略也可以有自己的选项,可以通过给git merge和/或git pull提供-X<option>参数来传递。
所以有时它会让人困惑,例如:
git将-Xours是我们的本地分支,- xtheir是他们的(远程)分支
git拉origin master -r where -Xours是他们的(远程),- xtheir是我们的
第二个例子与第一个相反,因为我们在远程分支的基础上重新建立了分支,所以我们的起点是远程分支,我们的更改被视为外部的。
git合并策略也类似(-X我们的和-X他们的)。
从git checkout的用法来看:
-2, --ours checkout our version for unmerged files
-3, --theirs checkout their version for unmerged files
-m, --merge perform a 3-way merge with the new branch
在解决合并冲突时,你可以执行git checkout—他们的some_file和git checkout—我们的some_file来分别将文件重置为当前版本和传入版本。
如果你已经完成了git checkout——我们的some_file或git checkout——他们的some_file,并想要将文件重置为文件的3向合并版本,你可以执行git checkout——merge some_file。
我们的:这是您目前所在的分支。
他们的:这是在你的行动中使用的另一个分支。
因此,如果你在分支版本/2.5上,你将分支feature/new-buttons合并到其中,那么在/2.5中找到的内容就是我们的内容,在feature/new-buttons上找到的内容就是他们的内容。在合并操作中,这是非常直接的。
大多数人陷入的唯一问题是rebase情况。如果您执行的是re-base而不是普通的合并,则角色将交换。这是怎么回事?嗯,这完全是由重基工作的方式引起的。想想rebase是这样工作的:
你上一次拉之后所做的所有提交都被移动到它们自己的分支中,我们将其命名为BranchX。
签出当前分支的头,丢弃任何本地分支
您所拥有的更改,但是通过这种方式检索其他人为该分支推送的所有更改。
现在BranchX上的每个提交都是按旧到新的顺序挑选的。
BranchX再次被删除,因此不会出现在任何历史记录中。
当然,事实并非如此,但这对我来说是一个很好的心智模型。如果你看第二和第三,你就会明白为什么角色互换了。在第2点,你的当前分支现在是来自服务器的分支,没有任何你的改变,所以这是我们的(你所在的分支)。您所做的更改现在在一个不同的分支上,而不是您当前的分支(BranchX),因此这些更改(尽管是您所做的更改)是他们的(在您的操作中使用的另一个分支)。
这意味着如果你合并,你想让你的改变总是赢,你会告诉git总是选择“我们的”,但如果你重新基数,你想让你的所有改变总是赢,你告诉git总是选择“他们的”。