I have many commits that need to be squashed (several thousand, we had a runaway script). Those commits are in groups between 40 to 200.
Using git rebase -i
is not feasible since it would involve too much labor. We have a tool, that can output the first and last commit of such a group relative from the branch HEAD (which can be used to get the actual commit by its reference hash).
So as an example I'm looking for something that can squash HEAD~400 to HEAD~200 into a single commit. And can then be run again (with change arguments) to squash HEAD~100 to HEAD~50 into another single commit.
I have thought about about creating a "fake" editor, that essentially fakes the interactiveness, by performing the changes to the rebase file. An abstract example script would look like this (which I could loop until all groups have been squashed):
start=$('get start of oldest group')
end=$('get end of oldest group')
git config core.editor "'~/fakeeditor' -start $start -end $end"
git rebase -i
First, create a script for manipulate the todo list of git rebase:
squash-it
file:
#!/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"
Then use this script like this:
GIT_SEQUENCE_EDITOR='sh -c "./squash-it HEAD~100 HEAD~50 $1"' GIT_EDITOR=cat git rebase -i HEAD~100^
You can replace squash
with fixup
if it’s what you want.
You can of course generate this line in a script itself that will replace HEAD~100
and HEAD~50
with your liking in a loop for instance.