Skip to content

Instantly share code, notes, and snippets.

@hoegaarden
Last active April 3, 2024 18:48
Show Gist options
  • Save hoegaarden/5c75d61ad223dc9ccca1c9fde9e501c4 to your computer and use it in GitHub Desktop.
Save hoegaarden/5c75d61ad223dc9ccca1c9fde9e501c4 to your computer and use it in GitHub Desktop.
git rebase, but keep author, committer & dates
#!/usr/bin/env bash
set -eu
set -o pipefail
usage() {
local me="$( basename "$0" | sed 's/^git-//' )"
cat <<EOF
git $me [target]
Does an interactive git rebase onto [target], but tries to keep the same
author, committer and author- and commit-dates as on the original commits
before the rebase.
This should give you somewhat the same UX as with a normal git rebase, the
todo list will just be a bit longer and inject \`exec\`s which after each
\`pick\` which reset the author & committer data back to the original.
EOF
}
genTodoList() {
local pick='pick %h %s'
local envAuthor="GIT_AUTHOR_NAME='%an' GIT_AUTHOR_EMAIL='%ae' GIT_AUTHOR_DATE='format:iso8601:%aI'"
local envCommitter="GIT_COMMITTER_NAME='%cn' GIT_COMMITTER_EMAIL='%ce' GIT_COMMITTER_DATE='format:iso8601:%cI'"
local amend="exec ${envAuthor} ${envCommitter} git commit --quiet --amend --reset-author --no-edit"
git log \
--reverse \
--format="${pick}%n${amend}%n" \
"${1}..HEAD"
}
genEditor() {
cat <<'EOF' | sed -e "s@__TODO__@${1}@g" -e "s@__EDITOR__@${2}@g"
#!/usr/bin/env bash
set -eu
set -o pipefail
sed 's/^/# /g' "$1" > '__TODO__.org'
{
cat '__TODO__'
echo
echo '# ----[ original todo list ]----'
cat '__TODO__.org'
} > "$1"
exec '__EDITOR__' "$@"
EOF
}
findDefaultEditor() {
[ -n "${GIT_EDITOR:-}" ] && { echo "$GIT_EDITOR" ; return ; }
[ -n "${EDITOR:-}" ] && { echo "$EDITOR" ; return ; }
[ -n "${VISUAL:-}" ] && { echo "$VISUAL" ; return ; }
command -v sensible-editor >/dev/null && { echo sensible-editor ; return ; }
echo 'vi'
}
main() {
if [ "$#" -ne 1 ]
then
usage >&2
exit 1
fi
local tempDir todo todoEditor defaultEditor target
tempDir="$( mktemp -d )"
# shellcheck disable=SC2064
trap "rm -rf -- '$tempDir'" EXIT
todo="${tempDir}/todo"
todoEditor="${tempDir}/editor"
defaultEditor="$( findDefaultEditor )"
target="$1"
genTodoList "$target" > "$todo"
genEditor "$todo" "$defaultEditor" > "$todoEditor"
chmod +x "$todoEditor"
GIT_EDITOR="$todoEditor" git rebase --interactive "${target}"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment