-
Notifications
You must be signed in to change notification settings - Fork 2
/
git-retimestamp
executable file
·77 lines (67 loc) · 2.89 KB
/
git-retimestamp
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
#!/bin/sh
### Rewind commit/author timestamps of N commits back to a
### specified offset compared to current values of each commit
### (C) 2019-2024 by Jim Klimov
set -u
set -e
[ -z "${DEBUG-}" ] || set -xv
[ -n "${BACK-}" ] || BACK=2
PREV=1
# For BSD could be OFFSET="-v-3d -v-9H'
[ -n "${OFFSET-}" ] || OFFSET="- 3 days"
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
}
[ -n "${GDATE-}" ] || {
# Should support "date -d ..."
(command -v gdate) && GDATE=gdate || GDATE=date
# Not covered here yet as a method (just a fallback below),
# but programs for BSD would use multi-token syntax like:
# date -f '%Y-%m-%d %H:%M:%S %z' -j -v '-3d' -v '-9H' "$DOLD"
# There are many different and incompatible implementations
# and it is hard to fall-back and cater to each of them.
# If the current system has a GNU date, we want to use it.
}
# 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="echo \"[\$#: \$@]\" >&2; $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:"
DOLD="`git show -s --format='%ci'`"
DNEW="`$GDATE -d \"$DOLD $OFFSET\"`" && [ -n "$DNEW" ] \
|| { DNEW="`$GDATE -f '%Y-%m-%d %H:%M:%S %z' $OFFSET -j \"$DOLD\"`" && [ -n "$DNEW" ] ; } \
|| { echo "FATAL: No compatible 'date' program was found for the OFFSET value (and other args) used" >&2 ; git rebase --abort; exit 1 ; }
echo "=== AMENDING:"
echo "=== OLD DATE: $DOLD"
echo "=== NEW DATE: $DNEW"
GIT_COMMITTER_DATE="$DNEW" GIT_AUTHOR_DATE="$DNEW" git commit --amend --no-edit --date "$DNEW"
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 "==============================================================================="
echo "DONE; if you want to 'git reset' to initial state, this was the starting point:"
echo "$INITLOG"
echo "==============================================================================="