2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GitAdvent Calendar 2021

Day 2

git diff -I<regex> --ignore-matching-lines=<regex>

Last updated at Posted at 2021-12-07

gitバージョン確認

git 2.30か2.31あたりで実装されたオプションのようです。

なんぞこれ?

diff の -I, --ignore-matchin-lines= と同様らしいです。
たとえばgitのソース(私が持ってきたのは以下のミラーです)で、

こちらには、git diffじゃなくて、diffのサンプルとして、htmlドキュメントインストール用にこんなスクリプトがあります。
(Documentation/install-webdoc.sh 抜粋)

T="$1"

for h in \
	*.txt *.html \
	howto/*.txt howto/*.html \
	technical/*.txt technical/*.html \
	RelNotes/*.txt *.css
do
	if test ! -f "$h"
	then
		: did not match
	elif test -f "$T/$h" &&
		$DIFF -u -I'^Last updated ' "$T/$h" "$h"
	then
		:; # up to date
	else
		echo >&2 "# install $h $T/$h"
		rm -f "$T/$h"
		mkdir -p $(dirname "$T/$h")
		cp "$h" "$T/$h"
	fi
done

ターゲットフォルダ($T)と手元のファイルを比較して、違いがあれば
コピーしますが、しかし、

$DIFF -u -I'^Last updated ' "$T/$h" "$h"

にあるように違いが '^Last updated ' の辺りだけであれば、変更なしとしてコピーはしないというものです。

この場合、実際に違うのは '^Last updated ' の次の行の日付の部分なのですが、diffの -I の場合はぢつはハンク単位でのマッチングということでこの記述でOKらしいです。diffの場合は。大事なので2度言っておきます。

参考にさせてもらったのはこちら

使ってみた

さて、 git diff -I ( git diff --ignore-matching-lines ) の場合ですけども、ぱっと思いつくのは、

git statusで「Changes not staged for commit」なファイルのうち、上記のような更新日付だけしか違わないようなファイル(ここではhtmlファイル)は git restore (git checkout) しちゃいたい。

上記diffで手元のhtmlと、インストール先のhtmlでやったことを、
カレントディレクトリとそのサブフォルダに対して、
作業ツリーのhtmlとHEADの対応するhtmlとの間で行います。

restore-htmls.sh
#!/bin/sh
git ls-files -m | while read line; do
    if test -e ${line} &&
	    git diff --quiet -I"^ [12][0-9][0-9][0-9]-[01][0-9]-[0123][0-9] [012][0-9]:[0-5][0-9]:[0-5][0-9] JST" -- ${line} &&
	    ! git diff --quiet -- ${line}
    then
	git restore -- ${line}
    fi
done

git ls-files -m は「Changes not staged for commit」なファイルのリストを得ます。この場合は現在のディレクトリとそのサブディレクトリの中全部から探してきてリストします。この時点ではhtml以外のファイルもリストされています。

! git diff --quiet -- ${line} 普通にdiff取って違いがあるかどうか一応確認しています。

git diff --quiet -I"^ [12][0-9][0-9][0-9]-[01][0-9]-[0123][0-9] [012][0-9]:[0-5][0-9]:[0-5][0-9] JST" -- ${line} 指定の正規表現の行だけ無視すれば違いが無い(この行以外に違いが無い)のであれば、そのファイルは編集前の状態に戻しちゃって構わないので git restore -- ${line} します。

git diffのオプションで差分アルゴリズム等をチューニングすればdiffと同様の記述でいけるのかもしれませんが、手元で試した時はdiffと同じファイルを扱っていても、git diff -Iの場合はこのようにマッチする行を厳密に指定する必要がありました。

-I --ignore-matching-lines の効果

正規表現に合致した行は違いと見なさない訳ですが、当該部分の差分出力自体が無くなる訳ではなくて、当該部分の差分出力は依然として行われます。単に exitcodeにカウントされるかしないかだけです。ここでは差分出力そのものは不要なので --quiet を指定しています。

--quiet

今回は差分出力そのものは必要ないので --quiet を指定します。 --quiet を指定すると --exit-code を指定したのと同じ効果もあります。

もし、 --quiet を外すのなら、必ず --exit-code を記述してください。そうしないと、git diffは差分ありなしではなく、gitコマンドの実行の成否(そしてそれはほとんどの場合、成功==0)を返してきます。しばらくハマっておりました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?