-
Notifications
You must be signed in to change notification settings - Fork 2
/
git-reauthor
executable file
·96 lines (82 loc) · 3.4 KB
/
git-reauthor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#!/bin/sh
### Change commit user (author) name and email for the last BACK commits
### (C) 2019-2024 by Jim Klimov
set -u
set -e
[ -n "${DEBUG-}" ] || set -xv
[ -n "${BACK-}" ] || BACK=2
PREV=1
[ -n "${COMMIT_USER_NAME-}" ] || COMMIT_USER_NAME="`git config user.name || git config --global user.name`"
[ -n "${COMMIT_USER_NAME-}" ] || { echo "COMMIT_USER_NAME or proper git config is required" >&2 ; exit 1; }
[ -n "${COMMIT_USER_EMAIL-}" ] || COMMIT_USER_EMAIL="`git config user.email || git config --global user.email`"
[ -n "${COMMIT_USER_EMAIL-}" ] || { echo "COMMIT_USER_EMAIL or proper git config is required" >&2 ; exit 1; }
[ "${SIGNOFF-}" = true ] || SIGNOFF=false
INITLOG="`git log -1`"
[ -n "${GSED-}" ] || {
# Historically: for expression below, sed should not claim
# bad flag in substitute command: '}'
# GIT_EDITOR="$GSED -e '0,/^pick /{s/^pick /edit /}' -i " git rebase -i HEAD~${PREV}
# Currently a POSIX-portable expression is used,
# but on a system with choices we might see some
# "very other" implementation so prefer GNU anyway.
(command -v gsed) && GSED=gsed || GSED=sed
}
ANEW="$COMMIT_USER_NAME <$COMMIT_USER_EMAIL>"
echo "Going back BACK=$BACK commits to change the commit authors to '$ANEW' ..."
[ -n "${COMMIT_USER_FILTER-}" ] && { echo "...matching regex '.*$COMMIT_USER_FILTER.*'" ; } \
|| { echo "You do not have COMMIT_USER_FILTER set, waiting a bit in case you need that" >&2 ; sleep 5; }
# Note that we must rewrite history starting from the newest
# commit, tracking back to the oldest, otherwise the edited
# timestamps tend to end up broken (reset to "today + offset").
# With the interactive rebase, the first line is the oldest
# commit of those selected (so fixing up the one PREV commits
# ago, one by one for different PREV values); watch out for
# merge-commits though!
while [ "$PREV" -le "$BACK" ] ; do
GIT_EDITOR="$GSED -e '/^pick /{s/^pick /edit /;:p' -e 'n;bp' -e '}' < \$1 > \$1.tmp && mv \$1.tmp \$1 ; : " git rebase -i HEAD~${PREV} && \
while sleep 0.1 ; do
echo "===== START COMMIT PARSE:"
AOLD="`git show -s --format='%an <%ae>'`"
echo "=== AMENDING:"
echo "=== OLD USER: $AOLD"
DO_AMEND=true
if [ -n "$COMMIT_USER_FILTER" ]; then
if expr "$AOLD" : ".*$COMMIT_USER_FILTER.*" > /dev/null ; then
echo "===== OLD USER matches the regex '$COMMIT_USER_FILTER'"
else
echo "===== OLD USER does not match the regex '$COMMIT_USER_FILTER', skipped"
DO_AMEND=false
fi
fi
if $DO_AMEND ; then
echo "=== NEW USER: $ANEW"
git commit --amend --no-edit --author "$ANEW"
if $SIGNOFF ; then
if git log -1 | grep "Signed-off-by: $ANEW" > /dev/null ; then
echo "===== ALREADY Signed-off-by: $ANEW" # no-op
else
echo "===== NEW SIGNATURE: Signed-off-by: $ANEW"
if [ -n "$COMMIT_USER_FILTER" ]; then (
GIT_EDITOR="$GSED -e '/^Signed-off-by: '"$COMMIT_USER_FILTER"'\$/d' < \$1 > \$1.tmp && mv \$1.tmp \$1 ; : " \
git commit --amend --author "$ANEW" -s
) ; else
git commit --amend --no-edit --author "$ANEW" -s
fi
fi
fi
fi
echo "=== RESULT LOG:"
git log -1
echo "=== CONTINUE REBASE:"
git rebase --continue || break
git status | grep rebasing || { echo "+++ DONE" && break ; }
echo "===== Next loop..."
echo ""
done
PREV="`expr $PREV + 1`"
echo "+++++++++++++++ NEXT CYCLE"
done
echo ""
echo ""
echo "DONE; if you want to 'git reset' to initial state, this was the starting point:"
echo "$INITLOG"