| #!/bin/sh | |
| # How much of the very original version from Linus survive? | |
| _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' | |
| _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" | |
| summary= | |
| while case $# in 0) break ;; esac | |
| do | |
| case "$1" in | |
| -s | --summary) | |
| summary=t | |
| ;; | |
| -*) | |
| echo >&2 "$1: unknown option" | |
| exit 1 | |
| ;; | |
| *) | |
| break | |
| ;; | |
| esac | |
| shift | |
| done | |
| if test $# = 0 | |
| then | |
| this=HEAD | |
| else | |
| this=$1 | |
| shift | |
| fi | |
| if test $# = 0 | |
| then | |
| initial=e83c5163316f89bfbde7d9ab23ca2e25604af290 | |
| range="..$this" | |
| else | |
| initial=$1 | |
| range="$initial..$this" | |
| shift | |
| fi | |
| this=$(git rev-parse --verify "$this^0") && | |
| initial=$(git rev-parse --verify "$initial^0") || exit | |
| tmp="/var/tmp/Linus.$$" | |
| trap 'rm -f "$tmp".*' 0 | |
| # We blame each file in the initial revision pretending as if it is a | |
| # direct descendant of the given version, and also pretend that the | |
| # latter is a root commit. This way, lines in the initial revision | |
| # that survived to the other version can be identified (they will be | |
| # attributed to the other version). | |
| graft="$tmp.graft" && | |
| { | |
| echo "$initial $this" | |
| echo "$this" | |
| } >"$graft" || exit | |
| opts='-C -C -C -w' | |
| show () { | |
| s=$1 t=$2 n=$3 | |
| p=$(($s * 100 / $t)) | |
| c=$(($s * 10000 / $t - $p * 100)) | |
| printf "%12d %12d %s (%d.%02d%%)\n" $s $t $n $p $c | |
| } | |
| empty_tree=$(git hash-object -t tree -w --stdin </dev/null) | |
| git diff-tree -r --raw $empty_tree $initial -- "$@" | | |
| while read mode_old mode_new sha1_old sha1_new op name | |
| do | |
| git blame $opts --porcelain -S "$graft" "$this..$initial" -- "$name" | | |
| sed -ne "s/^\($_x40\) .*/\1/p" | | |
| sort | | |
| uniq -c | { | |
| # There are only two commits in the fake history, so | |
| # there will be at most two output from the above. | |
| read cnt1 commit1 | |
| read cnt2 commit2 | |
| if test -z "$commit2" | |
| then | |
| cnt2=0 | |
| fi | |
| if test "$initial" != "$commit1" | |
| then | |
| cnt_surviving=$cnt1 | |
| else | |
| cnt_surviving=$cnt2 | |
| fi | |
| cnt_total=$(( $cnt1 + $cnt2 )) | |
| echo "$cnt_surviving $cnt_total $name" | |
| } | |
| done | { | |
| total=0 | |
| surviving=0 | |
| test -n "$summary" || | |
| printf "%12s %12s %s (survival%%)\n" surviving original path | |
| while read s t n | |
| do | |
| total=$(( $total + $t )) surviving=$(( $surviving + $s )) | |
| test -n "$summary" || | |
| show $s $t $n | |
| done | |
| if test -n "$summary" | |
| then | |
| echo $surviving $total | |
| else | |
| label=Total | |
| show $surviving $total $label | |
| fi | |
| } |