我正处于一场大规模的"进步中",伴随着无数的冲突.
我想把这个进展放在一边,并试图用另一种方法来解决这个问题.
有没有办法可以保存正在进行的 rebase,以便我可以在以后完成它?
如果你作为一个rebase的一部分坐在一个冲突的合并,你有点卡住.这就是为什么,如何以及你能做些什么.
从根本上说,Git中的rebase操作只是一系列挑选操作.我们从这样的事情开始:
...--A1--A2--A3--A4--A5 <-- branchA \ B1--B2--B3 <-- branchB
我们希望最终得到:
...--A1--A2--A3--A4--A5 <-- branchA \ \ \ B1'-B2'-B3' <-- branchB \ B1--B2--B3 [abandoned]
我们(或Git)实现这一目标的方法是使用git cherry-pick
或类似的东西来复制现有的提交B1
(将其转换为补丁并应用它)A5
,然后复制B2
到之后B1'
,依此类推.
交互式rebase实际上git cherry-pick
针对您在说明中留下的每个"选择"操作运行.非交互式rebase有几个选项,包括运行git cherry-pick
.
在挑选提交时,如果在应用时存在冲突,Git可以使用三向合并.这仍然可能因冲突而失败.这会阻止rebase.或者,当使用交互式rebase时,您可以选择"编辑"提交,在这种情况下,Git可以提交提交然后停止rebase的樱桃选择.在任何一种情况下,Git都会留下足够的信息让你让Git稍后重新获得rebase.
作为一个快速提醒,让我们注意Git的索引是你构建下一个提交的地方.正常情况下每个文件的一个条目被提交,因此,如果你的下一个承诺将包括只有三个命名的文件README
,file
以及otherfile
,将有三个索引条目.
请注意,索引与工作树是分开的,工作树包含正常的非Gitty格式的文件.与索引和存储库文件的内部Git格式不同,您可以编辑这些文件,编译它们,使用它们来提供网页等等.(工作树也可以保存未跟踪的文件,而不是在rebase期间这很重要.)
在冲突合并期间,每个索引条目都会公开其各个插槽.每个条目最多有四个插槽,并且它们已编号.Slot zero保存正常的,未冲突的文件(如果存在),否则为空.插槽1-3,如果在使用中,则保留必须解决的三个冲突部分.1 这些是基本版本(来自合并基础),"本地"或--ours
版本,以及其他--theirs
或有时"远程"版本.您的工作是编辑文件的工作树版本,解决冲突,然后解决git add
结果.这会将调整后的工作树版本复制到索引中的插槽零中,从而消除插槽1-3条目.现在文件已解析并准备提交.
1因此,任一时隙0被占用和1-3是空的,否则插槽0是空的和槽1-3被占用.有一些奇怪的情况,插槽1,2和/或3也可能是空的,例如,如果你得到修改/删除冲突或添加/添加冲突,但通常它是"0空意味着1-3已满"反之亦然.
非常短语的指数意味着只有一个.这基本上是正确的.
由于未合并状态是这个(下称"")的索引,并且只有一个指标,其他任何需要使用的索引不能进行直到完成解决冲突(然后进行提交).
如果您愿意,您可以简单地git add
使用未修复/未解决的项目和git commit
结果,只是为了解决冲突.这里的缺点是Git不会保留哪些文件存在冲突:你将删除插槽1-3条目,Git会认为你已经完成了.
你可以保存索引 - 它是一个普通的文件; 你可以把它从.git/index
其他地方复制出来.但是因为它是一个具有各种特殊内部使用的二进制文件 - 索引也称为"缓存",它会缓存内部文件系统数据以提高速度 - 这实际上并不十分安全.(如果Git有办法"导出"索引状态,然后再"导入"它,那么你真的可以保存并恢复合并冲突状态.但是Git没有.)
因此,为了安全起见,建议您完成解决此冲突的合并状态.或者,如果你还没有开始解决,甚至不要开始:那么就没有工作可以保存.
假设你开始我上面提到的"分支B"rebase,并且目前卡在复制提交的中间B2
,一些冲突尚未解决.这是你现在实际拥有的:
...--A1--A2--A3--A4--A5 <-- branchA \ \ \ B1' <-- HEAD \ B1--B2--B3 <-- branchB
索引处于冲突状态.你也有一个"独立的HEAD":Git正在以这种方式构建新的提交链.该名称HEAD
指向所有已完成的提交.
如果你已经做了一些解决工作,你应该完成它(因为它太难以保存未解决的状态)或者至少记下未解决的内容(因为你可以将文件添加到下一次提交中)然后运行git commit
以创建提交B2'
:
...--A1--A2--A3--A4--A5 <-- branchA \ \ \ B1'-B2' <-- HEAD \ B1--B2--B3 <-- branchB
如果你还没有做任何解决工作,那么就没有实际工作要保存,所以不要运行git commit
.但不管怎样,现在是时候创建一个分支或标记名称,指向HEAD
现在指向的同一个提交:
$ git branch saveme # or git tag saveme
现在你有了这个:
...--A1--A2--A3--A4--A5 <-- branchA \ \ \ B1'-B2' <-- HEAD, saveme \ B1--B2--B3 <-- branchB
现在你可以:
$ git rebase --abort
这让Git停止了rebase尝试并回到branchB
:
...--A1--A2--A3--A4--A5 <-- branchA \ \ \ B1'-B2' <-- saveme \ B1--B2--B3 <-- HEAD->branchB
现在你已经保存了迄今为止所做的所有工作,并且可以返回并稍后重试rebase.你拥有你(或Git)所做出的决议B1'
,如果你做了提交B2'
,你也可以获得解决方案.这些是提交saveme~1
和saveme
分别; 或者只是提交saveme
,如果只有一个提交.