【问题标题】:Is there an easy way to squash many commits in git?有没有一种简单的方法可以在 git 中压缩许多提交?
【发布时间】:2020-11-09 20:38:56
【问题描述】:

我有以下问题:
我有许多需要被压缩的提交(几千个,我们有一个失控的脚本)。这些提交在 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 rebase -i,而是一个自动压缩提交范围的命令。为什么不使用git rebase -i 并构建一个可以自动标记该待办事项列表中的提交范围的命令?
  • @NilsWerner 这是我已经建议使用那个“假编辑器”

标签: git git-rebase git-squash


【解决方案1】:

我个人最喜欢使用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 时的常见警告)。

【讨论】:

  • 显然是工作的工具。
【解决方案2】:

首先,创建一个用于操作 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 替换为您喜欢的循环。

【讨论】:

  • 好吧,拥有 shebang #!/bin/sh 并使用 bash -c 运行脚本有点奇怪,不是吗? :-) 为什么不直接使用 shebang #!/usr/bin/env bashGIT_SEQUENCE_EDITOR='./squash-it
  • 好的,我把它改成在任何地方都使用 sh
【解决方案3】:

您可以提前为git rebase -i 生成完整的命令列表,然后将它们粘贴到编辑器中。这个过程看起来像这样:

  1. 对于要压缩的每批提交,生成一个完整的提交哈希列表,前面带有单词fixup;假设您的开始和结束提交在$start$endgit 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 的变基工具将在您的列表中运行。

【讨论】:

    猜你喜欢
    • 2021-06-22
    • 2012-01-03
    • 2021-10-01
    • 2014-10-09
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    • 1970-01-01
    • 2011-01-03
    相关资源
    最近更新 更多