Have you ever had the need for a commit to be timestamped
with some time other than the moment you typed git commit
?
Perhaps you were supposed to have done some work yesterday,
or weren’t supposed to have done some work until after yesterday,
and you’d like git log
to reflect the, ahh, official truth.
Introducing git back
(With apologies to recovering nu metal fans. 1)
To set a specific point in history for git commit
, you’d think you can just use the --date
argument
, but this only sets the author date, per git commit --help
:
--date=<date>
Override the author date used in the commit.
… Wait, “only” sets the author date?
Indeed.
There is also the commit date.
Instead, the script below takes care to set both author and commit dates via environment variables.
This means it works not only with git commit
, but also with git merge
, which doesn’t take --date
argument.
You must enter the date in normal Git format,
which you can see via git back --help
or just refer to the dates in git log
.
Did you know you can make a program called git-SOMETHING
anywhere in your $PATH
,
and then run it as git SOMETHING
?
It feels like it’s just part of git.
In fact, much of git itself is built this way!
Drop this program into /usr/local/bin/git-back
(or wherever is appopriate for your environment)
and use history to tell whatever story you want, just like god intended.
git-back
source code (silent version)
#!/bin/sh
set -e
cmdname=`basename "$0"`
usage() {
cat << ENDUSAGE
git-back: [-h|--help] <date> <args...>
Run a git command as if on a certain date.
ARGUMENTS
date: A date in git format, like "Sun Aug 30 19:48:32 2020 -0500"
args: Arguments to send to git.
EXAMPLES
git-back "Sun Aug 30 19:48:32 2020 -0500" commit -a -m "Fix bug #123"
git-back "Sun Aug 30 19:48:32 2020 -0500" merge upstream/master
IMPLEMENTATION
All this does is set the GIT_COMMITTER_DATE and GIT_AUTHOR_DATE
and run a git command.
Note that running the simple 'git commit --date <date>' is not sufficient,
as it only sets one of those values.
There is also no --date option for 'git merge', which creates a commit.
The final word on date formatting comes from the
https://github.com/git/git/blob/master/Documentation/date-formats.txt
ENDUSAGE
}
if test $# -lt 1 || test "$1" = "-h" || test "$1" = "--help"; then
usage
exit
fi
date="$1"
shift
export GIT_COMMITTER_DATE="$date"
export GIT_AUTHOR_DATE="$date"
git "$@"
Most of the script is actually just its help, which I will also copy here:
> git back --help
git-back: [-h|--help] <date> <args...>
Run a git command as if on a certain date.
ARGUMENTS
date: A date in git format, like "Sun Aug 30 19:48:32 2020 -0500"
args: Arguments to send to git.
EXAMPLES
git-back "Sun Aug 30 19:48:32 2020 -0500" commit -a -m "Fix bug #123"
git-back "Sun Aug 30 19:48:32 2020 -0500" merge upstream/master
IMPLEMENTATION
All this does is set the GIT_COMMITTER_DATE and GIT_AUTHOR_DATE
and run a git command.
Note that running the simple 'git commit --date <date>' is not sufficient,
as it only sets one of those values.
There is also no --date option for 'git merge', which creates a commit.
The final word on date formatting comes from the
https://github.com/git/git/blob/master/Documentation/date-formats.txt
Audio upgrade
But what if you demand more from your custom git subcommands? What if you want to hear the name of the command yelled into the microphone by the lead singer of a rock band that was formed almost thirty years ago? What if you want to be surprised (and, dare I say, delighted?) every time you fabricate your commit history?
I, of course, have you covered.
git-back
source code (upgraded with audio)
#!/bin/sh
set -e
cmdname=`basename "$0"`
usage() {
cat << ENDUSAGE
git-back: [-h|--help] <date> <args...>
Run a git command as if on a certain date.
ARGUMENTS
date: A date in git format, like "Sun Aug 30 19:48:32 2020 -0500"
args: Arguments to send to git.
EXAMPLES
git-back "Sun Aug 30 19:48:32 2020 -0500" commit -a -m "Fix bug #123"
git-back "Sun Aug 30 19:48:32 2020 -0500" merge upstream/master
IMPLEMENTATION
All this does is set the GIT_COMMITTER_DATE and GIT_AUTHOR_DATE
and run a git command.
Note that running the simple 'git commit --date <date>' is not sufficient,
as it only sets one of those values.
There is also no --date option for 'git merge', which creates a commit.
The final word on date formatting comes from the
https://github.com/git/git/blob/master/Documentation/date-formats.txt
ENDUSAGE
}
# Download $HOME/.git-back.mp3 if it doesn't exist.
godsmack_dl() {
if type youtube-dl >/dev/null && type ffmpeg >/dev/null; then
if ! test -e "$HOME/.bad-religion.full.mp3"; then
youtube-dl --extract-audio --audio-format mp3 -o "$HOME/.bad-religion.full.mp3" 'https://www.youtube.com/watch?v=SS7bnB11QQ4'
fi
if ! test -e "$HOME/.git-back.mp3"; then
# -ss is start time; -t is duration of clip
ffmpeg -ss 0.25 -t 3.5 -i "$HOME/.bad-religion.full.mp3" "$HOME/.git-back.mp3"
fi
fi
}
# Play $HOME/.git-back.mp3 if it exists and you have a player installed.
godsmack_play() {
player=
for cmd in afplay mplayer mpg123 mpg321; do
if type $cmd >/dev/null; then
player=$cmd
break
fi
done
if test -e "$HOME/.git-back.mp3" && test "$player"; then
$player "$HOME/.git-back.mp3" &
fi
}
godsmack_play
if test $# -lt 1 || test "$1" = "-h" || test "$1" = "--help"; then
usage
exit
fi
if test "$1" = "godsmack"; then
godsmack_dl
godsmack_play
exit
fi
date="$1"
shift
export GIT_COMMITTER_DATE="$date"
export GIT_AUTHOR_DATE="$date"
git "$@"
Replace the previous, silent version of git-back
with this new upgraded version,
and then run git back godsmack
just once.
After that, git back
will loudly remind you what command you just typed each time you run it.
-
Related: did you know? ↩︎