git checkout --merge /-我们的----他们似乎在做同样的事情(错吗?)?

时间:2019-04-17 14:41:17

标签: git

我正在尝试从另一个分支合并(如果重要的话,这是一个孤立的分支)。但是,当我执行以下操作时:

git merge <branch-name>

它似乎已正确合并。但是,如果我这样做:

git checkout --merge <branch-name> -- <file-names>

如果不是全部,则当前分支上的大多数更改都将被清除。无论我使用--merge--ours还是--theirs,结果都是相同的。

我希望使用checkout标志时的--mergemerge会做同样的事情,除了指定的文件以外。

这是怎么回事?有我不明白的东西吗?

1 个答案:

答案 0 :(得分:4)

TL; DR

请参见the git merge-file command,该文档确实允许您执行所需的操作。

-m的{​​{1}}或--merge标志具有多种不同的含义。

当用于:

git checkout

或多或少具有您想要的含义;问题在于它适用于所有路径。

当用于:

git checkout -m <commit-specifier>

它具有不同的含义:这意味着Git应该针对git checkout -m [--] <paths> 中的每个命名路径,在具有(或具有)多个较高阶段的文件的工作树副本中重新创建合并冲突。索引条目。


这里还有一个更基本的问题。其中一部分只是棘手的用语(例如,我们都说“工作树中的变化”),而另一部分在于如何思考Git的工作:

  

...当前分支上所有 更改 的大部分(如果不是全部)被清除

这表明您正在考虑随着 更改而每个文件的工作树副本中包含什么,实际上并非如此。 Git不会在任何地方存储更改, 1 ,文件的工作树副本主要供您根据需要使用:Git主要使用快照,文件存储在我喜欢的冻结状态格式,与提交相关的 blob对象和索引中。

存在当前分支当前提交的概念,但是分支只是一个名称(存储在{{1} }),而提交是提交对象,则由其哈希ID(存储在分支名称中),永久(大部分)和不可变(全部)标识。提交间接包含每个源文件的完整快照。索引在Git中也是至关重要的,它也存储快照,但是与提交不同,索引中的内容是可变的。

同时,每个提交都存储一组 parent 提交的哈希ID,通常就是一个这样的提交。当您让Git向您显示一些提交时,Git实际上会从父提交提交本身提取所有文件, 2 然后 compares (全部两次提交中的文件,并显示您想要的不同。因此,当您查看提交时,它会显示进行更改。

Git使用索引做同样的事情:它将当前提交与索引进行比较,显示差异并调用为提交而进行的更改。然后,它将索引(如果您现在运行<paths>,则将索引(实际上是您建议的下一次提交快照)与工作树进行比较。无论索引和工作树之间有什么区别,Git都会显示出这些区别,称这些未针对提交进行的更改。但是在所有三组文件(提交的文件,索引中的文件和工作树中的文件)中,实际上没有更改,而是快照。 >

HEAD通常会做的事情-有很多例外,因为git commit实际上是多个不同的命令,所有命令都塞在一个面向用户的动词中-是从提交快照中提取文件,然后编写这些文件进入索引(​​以使索引和提交匹配),然后将索引副本写入工作树(以使索引和工作树匹配)。但是在执行任何上述操作之前,它会先比较当前对索引的提交和对工作树的索引,以确保不会丢失任何未保存的工作:如果这两个不匹配,则存在git checkout可能会破坏。

但是,一旦使用git checkout模式,您实际上将切换到完全不同的后端操作。此操作不是从提交开始,而是从索引开始。这些文件是过去某个时间从提交到索引的副本而复制的,因此索引具有一些文件集。该集合可能自上次正常检出或硬重置或其他原因以来已被更新:每个git checkout表示将文件从工作树复制到索引中,如果工作树文件与索引副本不匹配,好吧,现在可以了,因此索引中的文件集已更改。该索引甚至可能具有非零阶段条目,这些条目表示来自不完整的git checkout -- <paths>的持续合并冲突。在这种情况下,索引实际上存储的不是某些文件的三个冻干副本,从三个输入到更早的git add操作。 3 但是(一种或另一种),这种类型的git merge根本不返回提交:它只是从索引中获取文件并写入文件,或者是git merge重新合并它们,并破坏工作树中的所有内容。这样做而没有首先要问是否可以。 4

(编辑:也有git checkout,但这实际上调用了 third 模式。补丁操作可比较文件的两个版本,并让您选择该差异的一部分以应用到这两个版本之一,实际上是由在两个版本之间运行-m的Perl程序处理的,它实现了git checkout --patchgit diffgit checkout --patch和{{1 }}。

无论如何,最重要的是git add --patch不会执行您想要的操作。您可以获得所需的内容,但不使用git stash --patch。相反,您需要做的是提取要传递给git reset --patch的三个输入文件-将这三个文件放在任何位置;它们甚至不必位于存储库本身的工作树中,然后在它们上运行the git merge-file command


1 好,除非您存储git checkout -m -- path的输出,或者在特殊情况下,保存的合并的每个部分都与git checkout发生冲突,但是所有这些都低于正常可见度。

2 由于内部的冻干文件格式,Git实际上不必费心提取相同文件,只需提取至少相差一小部分的文件即可。

3 从技术上讲,每个文件最多可以 三个条目。在诸如修改/删除冲突的情况下,例如,对于某个文件,您只有两个条目。此外,当您完成解决合并冲突并git merge文件时,较高级的条目将消失。但是,在提交之前,这些较高级的条目将存储在类型为“ REUC”的秘密,不可见的索引条目中,尤其是使您可以使用git diff来恢复冲突。无法查看或保存此不可见条目,这是当前索引格式中的若干缺陷之一。

4 从用户友好的设计角度来看,这尤其糟糕,因为git rerere other 形式非常小心,不要丢失工作。< / p>