这听起来可能是一个太基本的问题,但我一直在寻找答案,现在我比以前更困惑了。
当我的分支合并到我的另一个分支时,“我们的”和“他们的”在git中是什么意思?
两个分支都是“我们的”。
在合并冲突中,“我们的”总是显示两个版本的上部吗?
“我们的”是否总是指合并开始时HEAD所指向的分支?如果是这样,那么为什么不使用一个明确的所有格,如“当前分支的”,而不是使用一个所有格代词,如“我们的”,这是指模棱两可的(因为两个分支在技术上都是我们的)?
或者只是使用分支名称(而不是说“我们的”,而是说“本地主人的”或类似的)?
最让我困惑的部分是,如果我在一个特定分支的.gitattributes文件中指定。让我们说在测试分支中,我有以下.gitattributes文件:
config.xml merge=ours
现在我签出并点HEAD到master,然后在测试中合并。因为master是我们的,test的.gitattributes没有签出,它会有影响吗?如果真的有效果,既然师父现在是“我们的”了,那又会怎样呢?
我们的:这是您目前所在的分支。
他们的:这是在你的行动中使用的另一个分支。
因此,如果你在分支版本/2.5上,你将分支feature/new-buttons合并到其中,那么在/2.5中找到的内容就是我们的内容,在feature/new-buttons上找到的内容就是他们的内容。在合并操作中,这是非常直接的。
大多数人陷入的唯一问题是rebase情况。如果您执行的是re-base而不是普通的合并,则角色将交换。这是怎么回事?嗯,这完全是由重基工作的方式引起的。想想rebase是这样工作的:
你上一次拉之后所做的所有提交都被移动到它们自己的分支中,我们将其命名为BranchX。
签出当前分支的头,丢弃任何本地分支
您所拥有的更改,但是通过这种方式检索其他人为该分支推送的所有更改。
现在BranchX上的每个提交都是按旧到新的顺序挑选的。
BranchX再次被删除,因此不会出现在任何历史记录中。
当然,事实并非如此,但这对我来说是一个很好的心智模型。如果你看第二和第三,你就会明白为什么角色互换了。在第2点,你的当前分支现在是来自服务器的分支,没有任何你的改变,所以这是我们的(你所在的分支)。您所做的更改现在在一个不同的分支上,而不是您当前的分支(BranchX),因此这些更改(尽管是您所做的更改)是他们的(在您的操作中使用的另一个分支)。
这意味着如果你合并,你想让你的改变总是赢,你会告诉git总是选择“我们的”,但如果你重新基数,你想让你的所有改变总是赢,你告诉git总是选择“他们的”。
我知道这个问题已经有答案了,但这个问题让我困惑了很多次,所以我建立了一个小的参考网站来帮助我记住:
https://nitaym.github.io/ourstheirs/
以下是基本原则:
合并:
$ git checkout master
$ git merge feature
如果你想在master中选择版本:
$ git checkout --ours codefile.js
如果您想在功能中选择版本:
$ git checkout --theirs codefile.js
重置:
$ git checkout feature
$ git rebase master
如果你想在master中选择版本:
$ git checkout --ours codefile.js
如果您想在功能中选择版本:
$ git checkout --theirs codefile.js
(当然,这是针对完整的文件)
我怀疑你在这里感到困惑,因为它从根本上令人困惑。更糟糕的是,当你在做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为这些引入了更多的名称,称它们为“本地”和“远程”!
我将把我的备忘录贴在这里,因为我必须一次又一次地回到这里。
场景1。普通开发人员:你是不能合并到精通的开发人员,只能使用功能分支。
案例1:主人是国王。你想要刷新你的特性分支(= rebase to master),因为master包含了新的依赖项更新,而你想要覆盖你的小改动。
git checkout master
git pull
git checkout feature
git rebase -X ours master
情况2:你是国王。你想要重新建立你的特性分支来控制变化。但是您比您的同事做得更多,并且希望优先使用您自己的更改。
git checkout master
git pull
git checkout feature
git rebase -X theirs master
重要提示:正如你所看到的,普通的开发人员应该更喜欢重新创建数据库,并像每天早上锻炼/喝咖啡一样重复它。
场景2。合并老师:你是一个团队领导,想合并其他分支,并将合并的结果直接推给一个主。Master是一个分支,你会改变。
案例1:master is a king您想要合并第三方分支,但master是优先级。Feature是你前辈做的一个分支。
git checkout feature
git pull
git checkout master
git merge -X ours feature
当你的高级开发人员发布了一个很酷的功能,你想要覆盖主分支中的旧的东西。
git checkout feature
git pull
git checkout master
git merge -X theirs feature
记住:在午夜记得该选择哪一个:主人永远是我们的。这是他们的特色。
从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。