Dav*_*arb 1 git merge rebase magit
我正在清理 git 存储库以使其更易于理解。到目前为止,它都是私人的,所以我可以改变历史。
大多数情况下,我一直将提交压缩成有意义的集合。
问题在于,该项目在其历史早期是其他两个项目的合并。我在压缩合并之前的提交时遇到问题。
我的问题是:我该怎么做?
具体来说:我有
xxxxxx * master: Latest commit
xxxxxx * another commit
xxxxxx * Merge projectA and projectB
xxxxxx |\
0000A6 | * a minor commit in project A
0000A5 | * another minor commit
Run Code Online (Sandbox Code Playgroud)
我想把 0000A5 和 0000A6 压在一起。
当我尝试交互式变基时,magit(我碰巧使用的 git 的 emacs 前端)警告我“尽管合并在变基范围内,但仍继续吗?” 当我继续时,它会失败(取自我的实际工作,而不是上面的简化示例)。我不确定合并之前的重新提交提交是否存在问题,或者其他问题(“未跟踪文件”行是可疑的,因为合并包括将客户端项目移动到更大的“client/”子目录中)项目。
Last commands done (5 commands done):
pick fb5de84 Simplified schema:
squash 96ac7ac Revert schema to full complexity
Next commands to do (29 remaining commands):
pick 4ad389a Just indentation, for readability
pick 4241835 First pass at schema
You are currently editing a commit while rebasing branch 'master' on 'ad91ab4'.
Untracked files:
client/
No changes
You asked to amend the most recent commit, but doing so would make
it empty. You can repeat your command with --allow-empty, or you can
remove the commit entirely with "git reset HEAD^".
Could not apply 96ac7ac7753c03e83b8c1296d892ce9c5fea44c7... Revert schema to full complexity
Run Code Online (Sandbox Code Playgroud)
这里似乎发生了一些事情。我不熟悉您正在使用的前端,但看起来它正在尝试自动执行变基操作,并在出现通常需要手动干预但不知道如何修复的暂停时进行救援。
虽然通过合并进行变基可能很棘手,但我认为这与当前的问题没有任何关系。在我看来,96ac7ac 只是 fb5de84 的恢复,所以当你将它们压缩在一起时,你会得到一个空的提交。这是允许的,但需要手动干预。(变基会停止,你会说类似的话git commit --allow-empty
,然后继续。)
您可以通过执行以下操作来确认 96ac7ac 是否真的是完美的恢复
git diff 96ac7ac fb5de84^
Run Code Online (Sandbox Code Playgroud)
如果是,并且您的前端无法适应变基所需的干预,那么您可以删除这两个提交,而不是压缩它们。
您可能遇到的下一件事是,除非您提供该选项,否则 rebase 将尝试使历史记录呈线性--preserve-merges
。我认为这就是您的前端警告您的内容,一旦您告诉它继续,我不知道它是否通过了该选项。
即使使用正确的选项,通过合并进行变基的问题是,超出默认自动解析范围的原始合并中的任何工作都可能会丢失。如果需要手动解决冲突,那么 git 将再次停止并期望您执行解决方案(您的前端可能不配合)。此外,如果自动解析成功,但合并包含手动应用的更改(幸运的是,这种情况很少见,但并非不可能),这些更改可能会悄然丢失。
另一种选择是“解决”合并(如果合并数量不是太多)。如果你有
X --- A --- B --- M --- C <--(master)
\ /
D --- E --- F
Run Code Online (Sandbox Code Playgroud)
你想挤压E
并且F
,那么你可以先
git checkout F
git checkout -b temp_branch
git rebase -i D
Run Code Online (Sandbox Code Playgroud)
并设置壁球,给你
X --- A --- B --- M --- C <--(master)
\ /
D --- E --- F
\
EF <--(temp_branch)
Run Code Online (Sandbox Code Playgroud)
然后重做合并
git checkout B
git merge temp_branch
Run Code Online (Sandbox Code Playgroud)
在此合并期间,您必须重现在原始合并中完成的所有工作M
。如果M
只是自动解析,那么 mew merge ( M'
) 也应该如此。您可以确认它是好的
git diff M M`
Run Code Online (Sandbox Code Playgroud)
如果这显示出差异,您将必须手动应用它们(这也可能是发生的情况M
)。我相信你可以让工作树看起来正确并做出承诺--amend
。
当然,如果合并信号发生冲突,您就必须解决它们;再次反对M
应该提供良好的指导。
完成此操作后,您将拥有
<*>- M --- C <--(master)
/
X --- A --- B --- M' <--((HEAD))
\ /
D --------- EF <--(temp_branch)
\
E --- F -<*>
Run Code Online (Sandbox Code Playgroud)
(抱歉,奇怪的符号,这张图让我着迷; s 应该是从到 的<*>
单行。但别担心,我们即将解开它。)F
M
清理并执行合并后提交的最终变基:
git branch --delete temp_branch
git rebase --onto M` M master
Run Code Online (Sandbox Code Playgroud)
屈服
X --- A --- B --- M' --- C` <--(master)
\ /
D --------- EF
Run Code Online (Sandbox Code Playgroud)
您可以看到这可能非常乏味,特别是如果有许多合并和/或包含手动冲突解决或其他非自动更改的合并。验证最终状态是关键。(您可以使用 reflog 来帮助解决此问题,或者在开始这一切之前标记原始主 HEAD。例如使用 reflog:
git diff master master@{1}
Run Code Online (Sandbox Code Playgroud)
如果您还想验证每个历史提交,这个符号可能会变得混乱......)
另一种变体是,您可以压缩然后设置一个 with 来重新设置父级 from to ,而不是重做合并并将合并后工作E
重新定F
基到其上。有关如何使用的详细信息,请参阅文档(尽管您必须稍微调整示例以处理合并)。这可能有效,因为您特别希望结果具有未更改的树。git filter-branch
--parent-filter
M
B , F
B , EF
git filter-branch
--parent-filter