当我创建一个孤立分支时,我必须删除所有文件,以便该分支完全为空。我希望能够对空分支进行另一次提交,但是我收到一个错误消息,指出该文件已在一个分支上被修改,但在另一个分支上已被删除。我希望避免手动解决这些冲突,因此最终可以使此过程自动化。有没有一种方法可以自动解决冲突以接受文件的修改版本?
答案 0 :(得分:1)
我还不清楚您想要什么样的结果,即您真正的目标是什么。但是,无论目标是什么,这可能都是错误的解决方法。
当创建一个孤立分支时,我必须删除所有文件,以便该分支完全为空。
这是正确的,但是是错误的。 :-)
更具体地说,让我们来看一下操作的各个部分以及所需的命令:
git checkout --orphan newbranch
:这会修改您当前的Git状态,以使您的 index 和 work-tree 保持不变,但是您位于分支{{ 1}},实际上还不存在。
newbranch
:这将根据您的 index 中的内容创建一个新的提交。 1 您的工作树无关紧要。如果您所在的分支不存在,例如步骤1中的git commit
,则具有创建分支的作用。现在,您所在的分支的尖端是刚刚创建的提交,而您刚进行的新提交的父级是分支上的先前提交-在步骤1产生的状态下,该提交为 no 提交,这样新的提交就没有 父级。
因此,当我说的是对的却是错误的时,我的意思是没有分支是空的。分支(或更准确地说,分支 name )指向一个特定的提交。该提交必须存在!该提交具有某些父项,如果该提交是根提交,则没有父项。如果您使用单词 branch 来表示松散指定的提交链,并以一个特定的提交结尾,则也永远不会是 empty 。您需要做的是清除 index ,因为Git会根据索引中的内容进行新的提交。
大概,您想要的是创建一个其中没有个文件的新提交。那不是一个空的分支!那是一个具有一个提交的分支(新的提交没有父级),其中一个提交具有空的 tree 。另请参见Is git's semi-secret empty tree object reliable, and why is there not a symbolic name for it?,但是对于此空树对象或使用该对象的提交只有有限的用途。
1 如果您不熟悉单词索引(也称为登台区域或缓存)的用法,并且工作树,请参见What's the difference between HEAD, working tree and index, in Git?。有关Git和Git用户倾向于合并称为 branch 的内容的更多信息,另请参见What exactly do we mean by "branch"?
我希望能够对空分支进行另一次提交,但是我收到一个错误消息,说该文件在一个分支上已被修改,而在另一个分支上已被删除。
由于空分支是没有意义的,因此我必须在这里猜测您的意思:您已经完成newbranch
来创建该分支git rm -r .; git commit
,该分支指向其树的提交是空树。现在,您有了一个带有一个根提交的孤立分支。如果您运行:
newbranch
Git会删除所有(跟踪的)文件,而索引为空。
如果您现在运行git checkout newbranch
,则会收到很多关于您所描述形式的投诉。那是因为是 。让我们绘制Git提交图的一部分:
git cherry-pick <hash>
也就是说,名称... <-F <-G <-H <-- master
I <-- newbranch (HEAD)
表示提交master
,这是我们的master分支的尖端。提交H
的父项(此处每个大写字母代表一个实际的哈希ID)是提交H
。 G
的父级是G
,其父级在F
范围内。
提交...
具有 no 父级;这是一个根提交。我们的I
附加在名称HEAD
上,该名称指向提交newbranch
。
在这一点上,运行I
会产生这些抱怨,原因是它正在将提交git cherry-pick <hash-of-G>
作为合并基础,F
作为{{1}进行三步合并},而I
为--ours
。三向合并包括运行两个 G
,以查看谁做了哪些工作:
--theirs
:这是他们所做的。 Git将git diff
中的快照与git diff --find-renames <hash-of-F> <hash-of-G>
中的快照进行比较,以查看它们发生了什么变化。
F
:这是我们 所做的。 Git将G
中的快照与git diff --find-renames <hash-of-F> <hash-of-I>
中的快照进行比较,以查看我们发生了什么变化。但是我们使用空树制作了F
,所以区别在于我们删除了每个文件!
现在,合并引擎的工作是将我们的更改(删除所有文件)与它们的更改进行合并,无论这些更改是什么。对于他们没有更改的任何文件,Git接受我们的更改并删除了该文件。对于它们 did 更改的任何文件,Git声明合并冲突。除非I
和I
中的树匹配,否则我们将确保至少有一个合并冲突,并且自动拾取将停止并让您完成工作。
是否有一种自动解决冲突的方法来接受文件的修改版本?
确定:使用F
在索引中的各个暂存槽中找到条目。对于第1阶段和第3阶段中存在的任何文件(即在合并基础和G
提交中,在此示例中为git ls-files --stage
和--theirs
),插槽中都没有文件2,因为我们删除了所有文件(在此示例中提交F
)。您的工作是用单个零级条目替换三个编号较高的登台插槽。您大概想要阶段3(从G
提交)到阶段0的文件,并且有一种简单的方法来获得该文件:I
工作树中文件的副本。
在这种特殊的冲突情况下,“被我们删除”并被“修改”,Git将修改后的文件保留在工作树以及暂存槽3中。因此--theirs
将把工作-tree复制到插槽0中,然后删除插槽1和3中的条目-在这种情况下,插槽2中没有任何要删除的内容。 (如果有的话,git add
会删除它,但是如果有的话,当前工作树中的内容可能不合适。)
由于每个文件都是这种情况,因此您可以简单地运行git add
来准备索引,然后运行git add
或git add .
来完成樱桃。 -pick并重新提交:
git cherry-pick --continue
新提交git commit
包含提交... <-F <-G <-H <-- master
I <-J <-- newbranch (HEAD)
中每个文件的副本,该副本不同于提交J
中相同文件的副本。提交G
保持着空树,因此几乎没有用。
如果提交F
确实是理想的结果,则有一种更简单的 2 方式来获得它:
I
和J
中的每个文件,如果文件匹配,则什么也不做,但是如果它们不同,则更新临时索引以保存F
的名称和哈希ID。 第2步是唯一困难的部分,但很容易实现自动化:
G
G
使git diff-tree -r --find-renames -z | ...automation-program...
递归到子目录中。 -r
和git diff-tree
是可选的:--find-renames
启用重命名检测器(否则,重命名文件从第一次提交中被-z
删除,--find-renames
被下移到第二个提交)和不同的名称),并且D
将差异数据安排为ASCII-NUL终止而不是换行符终止,并避免了“解引用”困难的文件名的需要(请参见the RAW OUTPUT FORMAT section of the git diff-tree documentation )。您必须自己编写自动化程序,但它只能使用从A
读取的模式和哈希信息,对每条缓存信息行调用-z
。
第1步包括导出一个环境变量git update-index --cacheinfo
,该变量指向一个不存在的临时文件的名称:Git随其创建。步骤3是运行git diff-tree
(相当于GIT_INDEX_FILE
的管道),然后使用git commit-tree
创建或更新引用名称以引用新的提交。您可以直接为git commit
选择父母,也可以完全不选择父母。有关用法,请参阅其文档。
2 好吧,计算上更容易。与仅运行git update-ref
相比,显然要进行更多工作。