I ended up using a bash script with the help of the linked question.
I'm attaching it for completeness's sake.
Note: My bash is ugly.
One thing of importance though: Since the script cannot accept arguments, I've opted for a self-modifying code.
If there's a better solution (without using globals/environment variables), I'd love to know.
Also, I'm not entirely sure how to swap two lines in bash (and google wasn't a great help), so I ended up using a for
loop.
#!/bin/bash
commit1=???
commit2=???
if [ "$#" -eq 2 ]; then #2 arguments, first phase of script
#modify lines 2 and 3 with arguments
currentFile=${BASH_SOURCE[0]}
cat $currentFile | sed "2s/.*/commit1=$1/" | sed "3s/.*/commit2=$2/" >| $currentFile
echo "$currentFile"
exit
fi
# second phase of script
line1=$(grep -nr "pick $commit1" $1 | cut -f1 -d:)
if [ -z $line1 ]; then
echo "Could not find a match for $commit1"
exit
fi
line2=$(grep -nr "pick $commit2" $1 | cut -f1 -d:)
if [ -z $line2 ]; then
echo "Could not find a match for $commit2"
exit
fi
oldLine=$(($line1<$line2?$line1:$line2))
newLine=$(($line1>$line2?$line1:$line2))
cat $1
#move newLine to be below oldLine, by iterating over all lines in reverse and swapping one by one
for currentLineIndex in `seq $newLine -1 $(expr $oldLine + 2)`; do
currentLine=$(sed -n "${currentLineIndex}p" "$1")
nextLineIndex=$(expr $currentLineIndex - 1)
nextLine=$(sed -n "${nextLineIndex}p" "$1")
cat $1 | sed $currentLineIndex"s/.*/$nextLine/" | sed $nextLineIndex"s/.*/$currentLine/" >| $1
done
#change the pick to squash
cat $1 | sed $(expr $oldLine + 1)"s/pick/squash/" >| $1
example use: $ GIT_SEQUENCE_EDITOR=$(./rebase.sh d199 a548) git rebase -i 95e2a7c