#!/bin/sh
# git blame の -w・-M・-C が、英語と日本語の行で元のコミットを見つけられるかを比べる。
# 一時ディレクトリに小さなリポジトリを 2 つ作るだけで、ほかの場所は変更しない。
# 使い方: sh blame-move-ja.sh
set -e
work=$(mktemp -d)
trap 'rm -rf "$work"' EXIT

EN='The quick brown fox jumps over the lazy dog near the river.
Pack my box with five dozen liquor jugs before the party.
How vexingly quick daft zebras jump over the fence today.'
JA='残存率は、書いてから測るまでの期間で大きく変わります。
同じ日に測っても、新しい行ほど高く出やすいと考えました。
そこで、測る時点を固定して数え直すことにしました。'
# 英数字の多い 1 行。日本語の行と一緒に移す
CMD='git blame --line-porcelain HEAD -- docs/guide.md | sort | uniq -c'
# 同じファイル内で入れ替える相手のブロック
EN2='Sphinx of black quartz, judge my vow and keep it safe.
The five boxing wizards jump quickly across the ring.
Jackdaws love my big sphinx of quartz on sunny days.'
JA2='空白だけを直したコミットでも、行の帰属は移ります。
行を別の場所へ移したときも、同じことが起きます。
どちらも、内容が変わっていないのに消えたと数えます。'

# 1 つ目のコミットに帰属する行数を数える。$1 = blame のオプション, $2 = ファイル
# 移し先にもとからある x の行と、一緒に移したコマンドの行は数えない
first() {
  git blame $1 --line-porcelain -- "$2" | awk -v root="$(git rev-list --max-parents=0 HEAD)" -v cmd="$CMD" '
    length($1) == 40 && $1 ~ /^[0-9a-f]+$/ { sha = $1 }
    /^	/ { text = substr($0, 2); if (sha == root && text != "x" && text != cmd) n++ }
    END { print n + 0 }'
}

try() {
  mkdir "$work/$1" && cd "$work/$1"
  git init -q . && git config user.name test && git config user.email test@example.com
  git config commit.gpgsign false   # 署名の設定があっても、一時リポジトリでは求めない
  printf '%s\n' "$2" "$3" > swap.md
  printf '%s\n' "$2" > from.md; printf 'x\n' > to.md
  printf '%s\n' "$2" > space.md
  printf '%s\n' "$CMD" "$2" > mixfrom.md; printf 'x\n' > mixto.md
  git add . && git commit -qm "1: 書く"
  printf '%s\n' "$3" "$2" > swap.md                          # 3 行ずつのブロックを入れ替える
  printf 'y\n' > from.md; printf '%s\n' "$2" >> to.md          # 3 行を別のファイルへ移す
  printf '%s\n' "$2" | sed 's/^/  /' > space.md                # 各行の先頭に空白を足す
  printf 'y\n' > mixfrom.md; printf '%s\n' "$CMD" "$2" >> mixto.md   # 英数字の多い行と一緒に 3 行を移す
  git commit -qam "2: 移す・空白を足す"
  echo "$1: 1 つ目のコミットに帰属する行"
  echo "  入れ替えた 6 行                  なし $(first '' swap.md)  -M $(first -M swap.md)"
  echo "  別のファイルへ移した 3 行        なし $(first '' to.md)  -C $(first -C to.md)"
  echo "  行頭に空白を足した 3 行          なし $(first '' space.md)  -w $(first -w space.md)"
  echo "  コマンドの行と一緒に移した 3 行  なし $(first '' mixto.md)  -C $(first -C mixto.md)"
}

(try 英語 "$EN" "$EN2")
(try 日本語 "$JA" "$JA2")
