假设以下历史记录:
X - Y - M - Z <- feature
/ /
A - B - C - D <- master
我想重写历史记录以将X和Y修复为单个提交。所以我希望历史看起来像这样:
X' - M'- Z' <- feature
/ /
A - B - C - D <- master
到目前为止,我所有的尝试都失败了。大多数时候在rebase期间存在冲突。也许rebase不是实现这个目标的正确方法吗?
我理解(不知道合并之前的有效情况还没有真正改变)重新应用从主设备到功能(M)的合并导致我在第一个地方解决的相同冲突。命令&#39; rerere&#39;可能是一个解决这个问题的选择,但据我所知,这只有在可以解决这个问题的情况下才有可能。一开始也被激活了。
但在这种情况下,X-Y确实具有与X&#39相同的变更集。为什么git不够聪明才能重新申请M?如果我只是在单个提交X&#39;中压缩X和Y,原始解析的更改(存储在M中)应该再次是M&#39;的正确内容。我怎么能告诉git只需要用M的旧内容来构建M&#39; ?
答案 0 :(得分:1)
echo `git rev-parse Y A` >.git/info/grafts
git filter-branch -- --all
rm .git/info/grafts
移植物是回复本地血统的覆盖物。看到祖先的git中的任何东西都会看到嫁接的祖先,特别是重写提交的东西会看到它并将其烘焙到重写的提交中。
过滤器是shell脚本片段,如果您想提供新的提交消息,例如
git filter-branch --msg-filter="
[ \$commit = `git rev-parse Y` ] && cat <&3 || cat" -- --all 3<<EOD
your new commit message subject
your new commit message body here
...
EOD
答案 1 :(得分:0)
git checkout feature
git checkout HEAD~2
git rebase -i HEAD~2
壁球最后两次提交。然后使用git cherry-pick
使用M
和Z
重写历史记录。
希望有所帮助。
答案 2 :(得分:0)
在我发现黑客时回答我的问题。我希望git可以做得更好/更容易,所以我仍然要求更好的解决方案...
黑客是在没有提交的情况下再次启动合并。然后将原始合并(M)中的所有更改读入索引并完成合并。需要重置才能清除工作目录中的冲突文件。之后继续樱桃采摘Z ...
git checkout -b featureRewritten A
git cherry-pick X
git cherry-pick -n Y
git commit --amend #this will actually fixup Y into X
git merge -n C #start the merge without commit
git read-tree M #throw away the staged merge results by
#replacing them with the original solution
git commit #finish commit. need to change the automsg?
git reset --hard HEAD #throw away any left overs
git cherry-pick Z #continue
历史悠久的艰苦工作......更好的解决方案?
答案 3 :(得分:0)
另一种解决方案(基于jthill的想法):
git checkout Y
git rebase -i A
#i-rebase: reword X
#i-rebase: fixup Y
git replace Y HEAD
git filter-branch -- --all --ancestry-path Y^!
git replace -d Y
首先结帐到分离的Y(一个以Y结尾的未命名分支)。交互式rebase将Y合并到X中并重新描述X的消息。结果是新的提交N.HEAD当前指向它。现在Y(仍然是分支特征的一部分)被N(HEAD)取代。使用filter-branch制作永久物。删除Y的替换以消除N.