Jul*_*n__ 2 git merge git-merge squash git-squash
我执行了多次merge提交,但它们应该是merge --squash相反的.解决冲突花了一天多的时间,所以我不能手工重做合并.
有没有办法将其转换merge为merge --squash?
tor*_*rek 12
这里值得注意git merge并且git merge --squash密切相关,但git merge --squash 不会创建合并.
这里的措辞非常重要,特别是"合并"前面的文章"a":"合并"是名词,而"合并"是动词.两个命令都执行合并操作.不同之处在于如何保存结果.
它还值得以提交图的形式快速提醒合并的外观.o这里的每个圆节点代表一个提交,早期提交向左.分支名称是指向一个特定提交的标签(分支的提示提交).你可以从这开始,例如:
...--o--*--o--o <-- main
\
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
然后,您决定将一个特定feature分支合并回main分支,因此您运行:
$ git checkout main && git merge feature
Run Code Online (Sandbox Code Playgroud)
这会进行合并(动词)并进行合并(名词),结果如下所示:
...--o--*--o--o---o <-- main
\ /
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
Git已经添加了一个新的提交main,并且这个新的提交是一个合并提交:它指向前一个提示main,并且还返回到(仍然是向下)的当前提示feature.(该名称feature继续指向与之前相同的提交.)
git merge --squash修改最后一步是什么.它没有进行合并提交,而是完全拒绝提交 - 没有明显的原因 - 并迫使你运行git commit.当你不运行git commit,这使得一个普通的承诺,而不是合并提交,以便结果如下:
...--o--*--o--o---o <-- main
\
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
这里有两个关键项目:
新提交的内容是相同的.这两个新提交都是从索引中创建的(索引是Git的术语,表示"你进行下一次提交的内容").此索引由merge-as-a-verb进程设置.第一个父级是"主线"提交,来自我们进行合并时所在的分支.在第二父是其他承诺,我们只是合并的一个.
新提交的父链接不同.真正的合并既有先前的提交作为其父项,但是"squash merge"只有一个先前的提交作为其父项 - "主线"提交.这意味着它不,它可以不记其呈交被合并项.
在冲突(但真实)合并的情况下,git merge无法自行进行新提交,因此它会停止并强制您解决冲突.一旦你完成了解决这些冲突,你必须手动运行git commit,就像你必须总是(没有明显的原因)做git merge --squash和它的假合并一样.您还可以请求任何真正的合并停止并让您使用检查结果git merge --no-commit.
这导致了一种简单的方法,只要真正的合并尚未提交,就可以将真正的合并转换为假(合并)合并:
对于git commit知道做一个合并,它依赖于由冲突(或者留下一个文件--no-commit)合并.此文件已命名.git/MERGE_HEAD.(它还留下了一个名为文件,.git/MERGE_MSG虽然这个额外的文件是无害的.)
因此,您只需删除 .git/MERGE_HEAD并运行即可git commit.(您可能希望删除MERGE_MSG文件,一旦您使用其消息编写了提交.在此之前,您可以将其用作消息,或作为其起点.)git commit步骤将不再知道合并提交,而不是做一个普通的提交 - 瞧,你已经进行了壁球合并.
如果您已经进行了真正的合并提交,则该过程可能会更难.特别是,如果您已发布合并,则现在必须让所有已获得此合并的人将其收回.否则,真正的合并将返回(它们可能会再次合并),或者为它们创建问题,甚至两者都会产生问题.但是,如果你可以这样做,或者如果它还没有发布,你只需要"将合并推到一边",就像它一样,然后进行虚假的合并提交.
让我们重新绘制我们拥有的东西,留出一些空间.这是与以前相同的图表,只是展开到更多行:
...--o--*----o----o
\ \
\ o <-- main
\ /
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
如果我们可以main返回到顶线,然后进行新的提交怎么办?好吧,我们会得到以下图纸:
...--o--*----o----o--o <-- main
\ \
\ o [abandoned]
\ /
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
请注意,所有箭头 - 包括提交用于记录历史记录的内部提交箭头(此处未显示,因为它们在文本绘图中难以生成) - 向左点,所以在任何顶线都没有任何知识承诺,在他们之下的任何承诺:这些都是"他们的权利".只有底线提交,再加上我们要放弃的提交,才能了解有关顶线提交的任何信息.
而且,如果我们要完全放弃中间线提交,那么让我们停止绘制它,以及它的两个合并箭头:
...--o--*----o----o--o <-- main
\
\
\
o--o--o <-- feature
Run Code Online (Sandbox Code Playgroud)
看看那个:我们刚刚绘制了我们想要的那种伪造壁球"合并"的提交图.只要我们在新提交中获得正确的内容,这正是我们想要的.
但是 - 这是一种练习; 看看你是否知道答案之前 - 新提交的内容来自何处? 在第一个要点中,上面用黑体字表示答案.(如果你忘了它,请回去检查.)
现在你知道git commit使用索引来进行新的提交,让我们考虑一下我们现在拥有的真正的合并提交.它有内容.(所有提交都有内容.)它们来自哪里?他们来自索引!如果我们能够以某种方式将这些内容重新带回索引,那么我们就是金色的.事实上,我们可以:我们所要做的就是检查提交,使用git checkout或已经将其作为当前提交.
由于我们刚刚进行了新的合并提交,因此我们已将合并提交作为当前提交.索引是干净的 - 如果我们运行git status,它说没有什么可以提交的.所以,现在我们使用git reset --soft来重置分支指针main退一万步,让我们中间图纸.该--soft参数告诉Git:"移动分支指针,但不要更改索引和工作树." 所以我们仍然会从原始合并中获得索引(和工作树).现在我们只是运行git commit进行普通提交,提供一些适当的提交消息,我们就完成了:我们有一个squash merge.原来的合并现在已经放弃,最终 - 在30天后的某个时间,默认情况下 - Git会注意到它已不再使用并将其删除.
(要向后移动一步,你可以使用HEAD~1或HEAD^;两者意味着相同的事情.因此命令序列就是这样git reset --soft HEAD^ && git commit,假设当前提交是你想用虚假合并替换的真正合并.)
即使您进行了多次合并提交,也可以使用上面的较长方法.但是,您必须决定是否需要多个假合并或一个大的假合并.例如,假设你有这个:
...--o--o---o--o--o <-- develop
\ \ / /
\ o--o / <-- feature1
\ /
o----o <-- feature2
Run Code Online (Sandbox Code Playgroud)
你想要你的最终照片看起来像:
...--o--o---o--o--o <-- develop
\ \
\ o--o <-- feature1
\
o----o <-- feature2
Run Code Online (Sandbox Code Playgroud)
最后两个提交的develop是两个假(壁球)合并,或者你只是想要一个大的假壁球:
...--o--o---o--o <-- develop
\ \
\ o--o <-- feature1
\
o----o <-- feature2
Run Code Online (Sandbox Code Playgroud)
哪个最后提交是最终结果?如果你想要两个假南瓜,你将需要保留两个原始的合并提交足够长的时间以使它们进入索引并从那些进行两次普通提交.如果你只想要一个最后合并的大型假壁球,那只需要两个Git命令:
$ git reset --soft HEAD~2 && git commit
Run Code Online (Sandbox Code Playgroud)
因为我们将保留第二个合并的索引,然后向后移动两个步骤,然后进行新的提交,将两个合并推到一边.
同样重要的是,没有任何真正的合并已经发布 - 或者,如果它们被发布,那么你说服其他已经捡起它们的人,就停止使用它们.