问题描述
我遇到以下问题:
我有很多提交需要压缩(数千个,我们的脚本失控了)。这些提交在40到200之间分组。
使用git rebase -i
是不可行的,因为它会涉及过多的工作。
我们有一个工具,可以从分支HEAD输出相对的此类组的第一个和最后一个提交(可用于通过其引用散列获取实际的提交)。
因此,作为示例,我正在寻找可以将HEAD〜400压缩为HEAD〜200的单个提交的东西。然后可以再次运行(带有更改参数)以将HEAD〜100压缩为HEAD〜50到另一个单个提交中。
编辑1:
我考虑过要创建一个“伪”编辑器,该伪编辑器实际上是通过对基准文件进行更改来伪造交互性的。一个抽象的示例脚本如下所示(我可以循环播放,直到所有组都被压缩为止):
start=$('get start of oldest group')
end=$('get end of oldest group')
git config core.editor "'~/fakeeditor' -start $start -end $end"
git rebase -i
解决方法
我个人最喜欢的是使用git reset --soft
。
因此,假设您要从HEAD~1000
开始压缩(HEAD~1000
是最后一个不会被压缩的生存提交):
git reset --soft HEAD~1000
git commit -m "Squashed a lot of stuff"
就是这样。您可以使用修订ID来代替HEAD~n
引用。
我看到你想按段来做....所以说....让我们将HEAD〜400挤压到HEAD〜200 ...然后从HEAD〜200挤压到HEAD〜100 ...然后从HEAD〜100到HEAD。因此,让我们创建一个临时分支,在该分支中进行工作。
git checkout -b temp HEAD~200
git reset --soft HEAD~400
git commit -m "squashing first segment"
# next segment
git checkout the-original-branch~100
git reset --soft temp
git commit -m "Second segment"
git branch -f temp #set temp over here
# final segment
git checkout --detach the-original-branch
git reset --soft temp
git commit -m "Final segment"
git branch -f temp #set temp over here
# if you like the result,feel free to move whatever branch over here
git branch -f whatever-branch
# and delete temp if so you want
git branch -D temp
我想很容易。
一天之后,我刚刚意识到(通过回答另一个问题),可以用一种更简单的方式来完成它:
git branch -f temp $( git commit-tree -p HEAD~400 -m "first squash" HEAD~200^{tree} )
# that set up temp on the first squash
git branch -f temp $( git commit-tree -p temp -m "second squash" HEAD~100^{tree} )
# temp has move to second squash
git branch -f temp $( git commit-tree -p temp -m "final squash" HEAD^{tree} )
现在temp已按我的示例请求的方式进行了压缩。随时在此处进行reset --hard
(使用reset --hard
时通常会发出警告)。
首先,创建一个脚本来操作git rebase的待办事项列表:
squash-it
文件:
#!/bin/sh
first=$(git rev-parse --short "$1")
last=$(git rev-parse --short "$2")
todo="$3"
lines=$(
sed -n "/^pick $first /,/^pick $last/{s/^pick/squash/p}" "$todo" | sed "1s/squash/pick/"
sed "/^pick $first /,/^pick $last/d" "$todo"
)
echo "$lines" > "$todo"
然后使用此脚本,如下所示:
GIT_SEQUENCE_EDITOR='sh -c "./squash-it HEAD~100 HEAD~50 $1"' GIT_EDITOR=cat git rebase -i HEAD~100^
如果需要,可以将squash
替换为fixup
。
您当然可以在脚本本身中生成此行,例如,您可以根据自己的喜好替换循环中的HEAD~100
和HEAD~50
。
您可以预先生成git rebase -i
的整个命令列表,然后将其粘贴到编辑器中。该过程如下所示:
- 对于要压缩的每一批提交,请生成完整的提交哈希表,其后带有单词
fixup
;假设您的开始和结束提交位于$start
和$end
中:git log "$start...$end" --pretty='fixup %h'
- 在每批提交之间,使用
pick
执行相同的操作;您可以将一组南瓜的末尾作为下一个南瓜的父类,然后作为下一个南瓜的父类,然后丢弃第一行:git log "$end...$nextStart^" --pretty='pick %h' | sed -n '2,$p'
- 在您要压扁的第一个提交之前找到提交,并以其为参数运行
git rebase -i
。 - 删除git生成的所有行,并将其粘贴到准备好的待办事项列表中。
- 保存并退出编辑器,git的变基工具将遍历您的列表。