どこでも見れるメモ帳

とあるSEの備忘録。何かあれば気軽にコメントください〜

gitで変更ファイルの差分行番号を取得するには?

はじめに

gitで変更ファイルの差分行内容とその行番号を取得したい状況が生じたためメモ(下画像は実行結果) Gyazo

やりかた

git --no-pager diff --no-ext-diff -U1000000 \
  | diff-lines.sh \
  | grep -E "^[^\"].*\:[0-9]+\:[\+|\-]"
  • 1行目について,git diffをファイル全行について標準出力*1.具体的には以下.
    • --no-pagerはgit diffを標準出力するオプション.デフォルトだとpagerにlessが設定されてしまうため,パイプに渡せるように指定
    • --no-ext-diffは外部diffを無効化するオプション.git diffをvimdiffで見るように設定していたため指定
    • -Uは行数を表示するオプション.例えば10を設定すると差分行まわりで10行が出力される.ファイル内容について全行出力したいため大きな値1000000を指定
  • 2行目について,diff-lines.shは以下とし*2,pathを通しておく.
  • 3行目について,変更のある行の取得.
#!/bin/sh
# diff-lines.sh
numbers
path=
line=
while read; do
  esc=$'\033'
  if [[ "$REPLY" =~ ---\ (a/)?.* ]]; then
    continue
  elif [[ "$REPLY" =~ \+\+\+\ (b/)?([^[:blank:]]+).* ]]; then
    path=${BASH_REMATCH[2]}
  elif [[ "$REPLY" =~ @@\ -[0-9]+(,[0-9]+)?\ \+([0-9]+)(,[0-9]+)?\ @@.* ]]; then
    line=${BASH_REMATCH[2]}
  elif [[ "$REPLY" =~ ^($esc\[[0-9;]+m)*([\ +-]) ]]; then
    echo "$path:$line:$REPLY"
    if [[ "${BASH_REMATCH[2]}" != - ]]; then
      ((line++))
    fi
  fi
done

補足

ファイル名と行番号だけで良い場合は以下のようにすればOK

git --no-pager diff --no-ext-diff -U1000000 \
  | diff-lines.sh \
  | grep -E "^[^\"].*\:[0-9]+\:[\+|\-]" \
  | ruby -nle 'print $_.split(":").slice(0..1).join(" ")' \ 
  | uniq

Gyazo

*1:Git - git-diff Documentation - http://git-scm.com/docs/git-diff

*2:Using git diff, how can I get added and modified lines numbers? - Stack Overflow - http://stackoverflow.com/questions/8259851/using-git-diff-how-can-i-get-added-and-modified-lines-numbers