Skip to content

Instantly share code, notes, and snippets.

@rsc
Created November 19, 2020 22:19
Show Gist options
  • Save rsc/f2817625d6d2ad7ca6e84474251d8932 to your computer and use it in GitHub Desktop.
Save rsc/f2817625d6d2ad7ca6e84474251d8932 to your computer and use it in GitHub Desktop.
#!/bin/bash
help="usage: git-generate
git-generate regenerates a commit from a script kept in the commit message.
Specifically, the topmost commit in the current git repo should have a script
preceded by [git-generate] on a line by itself. The script continues until the
end of the message or a Change-Id: line. The script starts execution in the
root of the git repo.
For example, a commit message might say:
We are moving from Old to New.
[git-generate]
cd some/dir
sed -i '' 's/Old/New/g' *
To regenerate the commit, git-generate resets the working file state to before
the commit and then runs the script. The script runs using 'bash -e', so any
single command failing will abort the generation.
"
if [ "$1" = "-help" -o "$1" = "-h" ]; then
echo "$help"
exit 0
fi
if [ $# != 0 ]; then
echo >&2 'usage: git-generate'
echo >&2 ' git-generate -help'
exit 2
fi
if ! git log -n1 >/dev/null; then
echo >&2 'git-generate: cannot find git repo'
exit 2
fi
set -e
gitdir=$(git rev-parse --show-toplevel)
what=HEAD
if [ -e $gitdir/.git/rebase-merge/stopped-sha ]; then
what=$(cat $gitdir/.git/rebase-merge/stopped-sha)
short=$(echo $what | cut -c 1-8)
echo >&2 "git-generate: using $short to resolve merge conflict"
fi
msg=$(mktemp /tmp/replayXXXXXX)
git log -n1 $what | sed -n 's/^ //p' | sed -n '/^ *\[git-generate\]$/,$p' | sed '1d; /Change-Id:/d' | grep -v Change-Id: >$msg
ls -l $msg
if ! [ -s $msg ]; then
echo >&2 'git-generate: no script found in commit'
exit 2
fi
now=$(git rev-parse HEAD)
# Reset files to HEAD^ but keep branch itself at HEAD.
# For a brief moment HEAD is pointing at HEAD^, which is unfortunate.
# It would be very nice if there were some single command to do this pair.
if [ what = HEAD ]; then
git reset -q --hard 'HEAD^'
git reset -q $now
else
# Resolving merge conflict, HEAD is parent before changes,
# which is exactly what we want.
git reset -q --hard HEAD
fi
cd $(git rev-parse --show-toplevel)
bash -e $msg
rm -f $msg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment