| 1 | #!/bin/sh |
| 2 | # How much of the very original version from Linus survive? |
| 3 | |
| 4 | _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' |
| 5 | _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" |
| 6 | |
| 7 | summary= |
| 8 | while case $# in 0) break ;; esac |
| 9 | do |
| 10 | case "$1" in |
| 11 | -s | --summary) |
| 12 | summary=t |
| 13 | ;; |
| 14 | -*) |
| 15 | echo >&2 "$1: unknown option" |
| 16 | exit 1 |
| 17 | ;; |
| 18 | *) |
| 19 | break |
| 20 | ;; |
| 21 | esac |
| 22 | shift |
| 23 | done |
| 24 | |
| 25 | if test $# = 0 |
| 26 | then |
| 27 | this=HEAD |
| 28 | else |
| 29 | this=$1 |
| 30 | shift |
| 31 | fi |
| 32 | |
| 33 | if test $# = 0 |
| 34 | then |
| 35 | initial=e83c5163316f89bfbde7d9ab23ca2e25604af290 |
| 36 | range="..$this" |
| 37 | else |
| 38 | initial=$1 |
| 39 | range="$initial..$this" |
| 40 | shift |
| 41 | fi |
| 42 | |
| 43 | this=$(git rev-parse --verify "$this^0") && |
| 44 | initial=$(git rev-parse --verify "$initial^0") || exit |
| 45 | |
| 46 | tmp="/var/tmp/Linus.$$" |
| 47 | trap 'rm -f "$tmp".*' 0 |
| 48 | |
| 49 | # We blame each file in the initial revision pretending as if it is a |
| 50 | # direct descendant of the given version, and also pretend that the |
| 51 | # latter is a root commit. This way, lines in the initial revision |
| 52 | # that survived to the other version can be identified (they will be |
| 53 | # attributed to the other version). |
| 54 | graft="$tmp.graft" && |
| 55 | { |
| 56 | echo "$initial $this" |
| 57 | echo "$this" |
| 58 | } >"$graft" || exit |
| 59 | |
| 60 | opts='-C -C -C -w' |
| 61 | |
| 62 | show () { |
| 63 | s=$1 t=$2 n=$3 |
| 64 | p=$(($s * 100 / $t)) |
| 65 | c=$(($s * 10000 / $t - $p * 100)) |
| 66 | printf "%12d %12d %s (%d.%02d%%)\n" $s $t $n $p $c |
| 67 | } |
| 68 | |
| 69 | empty_tree=$(git hash-object -t tree -w --stdin </dev/null) |
| 70 | |
| 71 | git diff-tree -r --raw $empty_tree $initial -- "$@" | |
| 72 | while read mode_old mode_new sha1_old sha1_new op name |
| 73 | do |
| 74 | git blame $opts --porcelain -S "$graft" "$this..$initial" -- "$name" | |
| 75 | sed -ne "s/^\($_x40\) .*/\1/p" | |
| 76 | sort | |
| 77 | uniq -c | { |
| 78 | # There are only two commits in the fake history, so |
| 79 | # there will be at most two output from the above. |
| 80 | read cnt1 commit1 |
| 81 | read cnt2 commit2 |
| 82 | if test -z "$commit2" |
| 83 | then |
| 84 | cnt2=0 |
| 85 | fi |
| 86 | if test "$initial" != "$commit1" |
| 87 | then |
| 88 | cnt_surviving=$cnt1 |
| 89 | else |
| 90 | cnt_surviving=$cnt2 |
| 91 | fi |
| 92 | cnt_total=$(( $cnt1 + $cnt2 )) |
| 93 | echo "$cnt_surviving $cnt_total $name" |
| 94 | } |
| 95 | done | { |
| 96 | total=0 |
| 97 | surviving=0 |
| 98 | test -n "$summary" || |
| 99 | printf "%12s %12s %s (survival%%)\n" surviving original path |
| 100 | while read s t n |
| 101 | do |
| 102 | total=$(( $total + $t )) surviving=$(( $surviving + $s )) |
| 103 | test -n "$summary" || |
| 104 | show $s $t $n |
| 105 | done |
| 106 | if test -n "$summary" |
| 107 | then |
| 108 | echo $surviving $total |
| 109 | else |
| 110 | label=Total |
| 111 | show $surviving $total $label |
| 112 | fi |
| 113 | |
| 114 | } |