有没有一种简单的方法来压缩git中的许多提交?

问题描述

我遇到以下问题:
我有很多提交需要压缩(数千个,我们的脚本失控了)。这些提交在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~100HEAD~50

,

您可以预先生成git rebase -i的整个命令列表,然后将其粘贴到编辑器中。该过程如下所示:

  1. 对于要压缩的每一批提交,请生成完整的提交哈希表,其后带有单词fixup;假设您的开始和结束提交位于$start$end中:git log "$start...$end" --pretty='fixup %h'
  2. 在每批提交之间,使用pick执行相同的操作;您可以将一组南瓜的末尾作为下一个南瓜的父类,然后作为下一个南瓜的父类,然后丢弃第一行:git log "$end...$nextStart^" --pretty='pick %h' | sed -n '2,$p'
  3. 在您要压扁的第一个提交之前找到提交,并以其为参数运行git rebase -i
  4. 删除git生成的所有行,并将其粘贴到准备好的待办事项列表中。
  5. 保存并退出编辑器,git的变基工具将遍历您的列表。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...