Last active
August 14, 2017 21:51
-
-
Save rsvp/fd93e0b86f325454fbce2b57cabd4ce0 to your computer and use it in GitHub Desktop.
git-lu :: Git script gets LAST COMMIT DATE / TIMES (since modification time is unreliable), given path/filename(s) -- supports wildcards, SHA hash ref.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# bash 4.3.11(1) Linux 3.13.0 git 1.9.1 Date : 2017-08-14 | |
# | |
# _______________| git-lu : get last commit date for file(s) | |
# since git can change OS file modification times! | |
# | |
# Usage: git lu [filename(s), wildcards optional] | |
# | |
# Example: $ git lu *.ipynb # SAMPLE OUTPUT FORMATTING | |
# 0000-00-00 _Not_committed _No_SHA 00-tpl-v4.ipynb | |
# 2014-12-07 12:02:38 -0800 362d82c fred-wage-capital.ipynb | |
# 2015-01-17 13:38:57 -0800 1530474 fred-debt-pop.ipynb | |
# | |
# Dependencies: git-log (built-in) | |
# | |
# CHANGE LOG | |
# 2017-08-14 Error code 117 for get_data fail. | |
# 2017-08-11 First version. | |
# _____ PREAMBLE_v3: settings, variables, and error handling. | |
# | |
LC_ALL=POSIX | |
# locale means "ASCII, US English, no special rules, | |
# output per ISO and RFC standards." | |
# Esp. use ASCII encoding for glob and sorting characters. | |
shopt -s extglob | |
# ^set extended glob for pattern matching. | |
shopt -s failglob | |
# ^failed pattern matching signals error. | |
set -e | |
# ^errors checked: immediate exit if a command has non-zero status. | |
set -o pipefail | |
# ^exit status on fail within pipe, not (default) last command. | |
set -u | |
# ^unassigned variables shall be errors. | |
# Example of default VARIABLE ASSIGNMENT: arg1=${1:-'foo'} | |
arg1=${1:-'NULL'} | |
program=${0##*/} # similar to using basename | |
memf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX ) | |
mem2=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX ) | |
errf=$( mktemp /dev/shm/88_${program}_tmp.XXXXXXXXXX ) | |
cleanup () { | |
# Delete temporary files, then optionally exit given status. | |
local status=${1:-'0'} | |
rm -f $memf $mem2 $errf | |
[ $status = '-1' ] || exit $status # thus -1 prevents exit. | |
} #-------------------------------------------------------------------- | |
warn () { | |
# Message with basename to stderr. Usage: warn "message" | |
echo -e "\n !! ${program}: $1 " >&2 | |
} #-------------------------------------------------------------------- | |
die () { | |
# Exit with status of most recent command or custom status, after | |
# cleanup and warn. Usage: command || die "message" [status] | |
local status=${2:-"$?"} | |
# cat $errf >&2 | |
cleanup -1 && warn "$1" && exit $status | |
} #-------------------------------------------------------------------- | |
trap "die 'SIG disruption, but cleanup finished.' 114" 1 2 3 15 | |
# Cleanup after INTERRUPT: 1=SIGHUP, 2=SIGINT, 3=SIGQUIT, 15=SIGTERM | |
trap "die 'unhandled ERR via trap, but cleanup finished.' 116" ERR | |
# Cleanup after command failure unless it's part of a test clause. | |
# | |
# _______________ :: BEGIN Script :::::::::::::::::::::::::::::::::::::::: | |
# __________ PRE-QUALIFY command-line parameters now | |
# because git-log error message is ugly. | |
[ "$arg1" = 'NULL' ] && die "SPECIFY filename(s), wildcards optional." 113 | |
# ___ since "in" is omitted, positional parameters assumed, i.e. "$@" | |
for file ; do | |
[ -e "$file" ] || die "INVALID file specified: $file" 115 | |
done | |
# __________ MAIN function | |
get_date () { | |
# ^Expects a single filename as $1 argument... | |
git log -1 --pretty="%ci %h" -- "$1" > $mem2 2>> $errf | |
# %ci is commit date ISO style: 2017-08-04 09:30:06 -0700 | |
# %cd would be commit date without time portion. | |
# %h gives short SHA hash (%H for full hash) | |
[ -s $mem2 ] && cat $mem2 || echo "0000-00-00 _Not_committed _No_SHA" | |
# UNCOMMITTED file gets ZEROS date and _No_SHA reference. | |
} | |
# ___ since "in" is omitted, positional parameters assumed, i.e. "$@" | |
for file ; do | |
echo "$(get_date "$file") $file" | |
done > $memf | |
[ -s $errf ] && die "get_date FAIL. Must be within a git repository." 117 | |
# __________ Post-production | |
# [ ] - Possibly add colors for readability... | |
sort $memf | |
# Dates sorted from 0000-00-00 to most recent commit date. | |
# Minor discrepancies possible if commits come from different time zones. | |
cleanup # Instead of: trap arg EXIT | |
# _______________ EOS :: END of Script :::::::::::::::::::::::::::::::::::::::: | |
# vim: set fileencoding=utf-8 ff=unix tw=78 ai syn=sh : |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Installation
The script should be placed within the scope of your $PATH.
By convention, git itself should be able to access this shell script
by the way it is named (see Example).
The script properly handles ignored and uncommitted files as well.
Story
For my Linux shell:
ls -l -A -t -r
is aliased to lu which is time-sorted.The script above is the git analogue since OS modification times cannot be
relied upon as last commit times.
By the way, lu is French for "read" (past tense).
Shortcut to this gist: https://git.io/git-lu