ちょっと話題の記事

Gitリポジトリ内をgrepする git grep はシンプルで超便利

Gitリポジトリ内を検索する機会はよくあると思います。git grepコマンドを使えば、git管理下のファイルのみを対象としてgrepができます。シンプルなコマンドですが、利便性はとても高いと思います。 「このメソッドって、どこで使われてるんだっけ?」 「その定数の定義って、値は何だっけ? どこにあるんだっけ?」 「あのURLって、何箇所で使われているんだろう?」
2020.01.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Gitリポジトリ内を検索する機会はよくあると思います。

  • このメソッドって、どこで使われてるんだっけ?
  • その定数の定義って、値は何だっけ? どこにあるんだっけ?
  • あのURLって、何箇所で使われているんだろう?

git grepコマンドを使えば、Git管理下のファイルのみを対象としてgrepができます。 シンプルなコマンドですが、利便性はとても高いと思います。

なお、grep対象はカレントブランチのみです。

目次

シンプルな例

シンプルな例ですが、よく使います。

特定ワードを含む箇所を調べたい(大文字小文字を区別する)

一番シンプルな例です。大文字小文字の区別をするので、注意が必要です。

なお、ワードの指定は正規表現(基本)です。正規表現(拡張)を使う場合は、-Eオプションを使います。

$ git grep "lambda"
hello_world/slash_command.py:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:def lambda_handler(event, context) -> dict:
template.yaml:      Handler: slash_command.lambda_handler
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

特定ワードを含む箇所を調べたい(大文字小文字を区別しない)

-iオプションを使います。

$ git grep -i "Lambda"
hello_world/slash_command.py:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:def lambda_handler(event, context) -> dict:
template.yaml:        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
template.yaml:      Handler: slash_command.lambda_handler
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

行番号を表示したい

-nオプションを使います。

$ git grep -n "lambda"
hello_world/slash_command.py:4:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:7:def lambda_handler(event, context) -> dict:
template.yaml:32:      Handler: slash_command.lambda_handler
tests/unit/test_handler.py:74:    ret = app.lambda_handler(apigw_event, "")

行番号表示は、Gitの設定でデフォルトONにできます。

$ git config --global grep.lineNumber true

正規表現(拡張)で検索したい

-Eオプションを使えば、正規表現(拡張)の表記で検索ができます。

次の例は「数字が2つ並んでいる箇所」です。

$ git grep -E "[0-9]{2}"
hello_world/common_lambda.py:    if res.status_code == 200:
hello_world/requirements.txt:requests==2.20.0
hello_world/slash_command.py:            "statusCode": 200,
template.yaml:AWSTemplateFormatVersion: '2010-09-09'
template.yaml:Transform: AWS::Serverless-2016-10-31
template.yaml:    Timeout: 10

単語で検索したい

-wオプションを使います。

$ git grep -w  "Function"
template.yaml:  Function:
template.yaml:    Type: AWS::Serverless::Function
template.yaml:    Type: AWS::Serverless::Function

ちなみに-wオプションが無い場合は次のような感じです(増えてますね)。

$ git grep  "Function"
template.yaml:  Function:
template.yaml:  NotifyPeriodicFunction:
template.yaml:    Type: AWS::Serverless::Function
template.yaml:  NotifySlashCommandFunction:
template.yaml:    Type: AWS::Serverless::Function

なお次を単語とみなしているようです。

  • 行の先頭で始まる or 頭に単語以外の文字がある
  • 行の終わりで終わるか or 単語以外の文字が続く

少し便利な例

ニッチな事例かもしれませんが、たまに役立つかもしれません。

特定フォルダのみで検索したい

-- <dir_name>を使用します。

$ git grep lambda -- hello_world/
hello_world/periodic.py:from common_lambda import get_notify_delays, get_message
hello_world/periodic.py:def lambda_handler(event, context) -> None:
hello_world/slash_command.py:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:def lambda_handler(event, context) -> dict:

特定フォルダを除外して検索したい

-- :^<dir_name>を使用します。:^がポイントです。

$ git grep lambda -- :^hello_world/
template.yaml:      Handler: periodic.lambda_handler
template.yaml:      Handler: slash_command.lambda_handler
tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

複数のワードを調べたい

--and--orが使えます。ついでに--notも使えます。パターンは-eで指定する必要があります。

and

$ git grep -e lambda --and -e app
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

or

$ git grep -e lambda --or -e app
hello_world/common_lambda.py:                notify_delays.append(check_item)
hello_world/common_lambda.py:        details.append(f'・{company}: {name}: <{website}|こちら>')
hello_world/periodic.py:from common_lambda import get_notify_delays, get_message
hello_world/periodic.py:def lambda_handler(event, context) -> None:
hello_world/slash_command.py:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:def lambda_handler(event, context) -> dict:
template.yaml:      Handler: periodic.lambda_handler
template.yaml:      Handler: slash_command.lambda_handler
tests/unit/test_handler.py:from hello_world import app
tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):
tests/unit/test_handler.py:        app.requests, 'get', side_effect=requests_response_mock)
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

表示時にファイル毎に空行を入れて見やすくする

--breakオプションを使います。

$ git grep --break lambda
hello_world/periodic.py:from common_lambda import get_notify_delays, get_message
hello_world/periodic.py:def lambda_handler(event, context) -> None:

hello_world/slash_command.py:from common_lambda import get_notify_delays, get_message
hello_world/slash_command.py:def lambda_handler(event, context) -> dict:

template.yaml:      Handler: periodic.lambda_handler
template.yaml:      Handler: slash_command.lambda_handler

tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):
tests/unit/test_handler.py:    ret = app.lambda_handler(apigw_event, "")

不一致な行を調べたい

-vオプションを使います。あまり使いどころはないかもしれませんが……。

$ git grep -v "lambda"
...(略)...
template.yaml:Description: Notify Slack Train Delay
template.yaml:
template.yaml:Globals:
template.yaml:  Function:
template.yaml:    Timeout: 10
template.yaml:
template.yaml:Resources:
template.yaml:
template.yaml:  NotifyPeriodicFunction:
template.yaml:    Type: AWS::Serverless::Function
...(略)...

一致した行の上側を表示したい

-B <num>オプションを使います。<num>には数値を指定します。

次の例だと、「lambdaがヒットした行と上側の2行」を表示しています。

$ git grep -B 2 lambda
template.yaml-    Properties:
template.yaml-      CodeUri: hello_world/
template.yaml:      Handler: periodic.lambda_handler
--
template.yaml-    Properties:
template.yaml-      CodeUri: hello_world/
template.yaml:      Handler: slash_command.lambda_handler
--
tests/unit/test_handler.py-
tests/unit/test_handler.py-
tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):

一致した行の下側を表示したい

-A <num>オプションを使います。<num>には数値を指定します。

次の例だと、「lambdaがヒットした行と下側の2行」を表示しています。

$ git grep -A 2 lambda
template.yaml:      Handler: periodic.lambda_handler
template.yaml-      Runtime: python3.6
template.yaml-      Policies:
--
template.yaml:      Handler: slash_command.lambda_handler
template.yaml-      Runtime: python3.6
template.yaml-      Events:
--
tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):
tests/unit/test_handler.py-
tests/unit/test_handler.py-    requests_response_mock = namedtuple("response", ["text"])

一致した行の上下を表示したい

-C <num>オプションを使います。<num>には数値を指定します。

次の例だと、「lambdaがヒットした行と上下の2行」を表示しています。

(「周辺をちょっと見たい」場合に使えそうですが、そのようなケースに遭遇したことはないです……)

$ git grep -C 2 lambda
template.yaml-    Properties:
template.yaml-      CodeUri: hello_world/
template.yaml:      Handler: periodic.lambda_handler
template.yaml-      Runtime: python3.6
template.yaml-      Policies:
--
template.yaml-    Properties:
template.yaml-      CodeUri: hello_world/
template.yaml:      Handler: slash_command.lambda_handler
template.yaml-      Runtime: python3.6
template.yaml-      Events:
--
tests/unit/test_handler.py-
tests/unit/test_handler.py-
tests/unit/test_handler.py:def test_lambda_handler(apigw_event, mocker):
tests/unit/test_handler.py-
tests/unit/test_handler.py-    requests_response_mock = namedtuple("response", ["text"])

一致した行を含む関数を表示したい

-Wオプションを使います。

関数の場合は良い感じにしてくれそうですが、YAMLファイルとか単なるTextファイルなどの場合は微妙です……(仕方がない)。

$ git grep -W lambda
hello_world/periodic.py:def lambda_handler(event, context) -> None:
hello_world/periodic.py-
hello_world/periodic.py-    notify_delays = get_notify_delays()
hello_world/periodic.py-
hello_world/periodic.py-    if not notify_delays:
hello_world/periodic.py-        # 遅延が無ければ通知しない
hello_world/periodic.py-        return
hello_world/periodic.py-
hello_world/periodic.py-    # Slack用のメッセージを作成して投げる
hello_world/periodic.py-    (title, detail) = get_message(notify_delays)
hello_world/periodic.py-    post_slack(title, detail)
hello_world/periodic.py-
hello_world/periodic.py-    return

ファイル名の一覧を調べたい

-lオプションを使います。「xxxメソッドを変更するため、対象ファイルを知りたい」とかで使ってます。

$ git grep -l lambda
hello_world/periodic.py
hello_world/slash_command.py
template.yaml
tests/unit/test_handler.py

一致した数を調べたい(ファイル毎)

-cオプションを使います。

$ git grep -c lambda
hello_world/periodic.py:2
hello_world/slash_command.py:2
template.yaml:2
tests/unit/test_handler.py:2

一致した数を調べたい(全体)

wc -lコマンドと組み合わせて、改行の数をカウントしています。

$ git grep lambda | wc -l
       8

一致した数を調べたい(ファイル数)

こちらもwc -lコマンドと組み合わせます。

$ git grep -l lambda | wc -l
       4

複数ファイルの特定文字列を置換する(Git管理ファイルのみ)

ファイル一覧を取得して、後段で1ファイルずつ置換処理させています。

$ git grep -l '検索対象の文字列' | xargs sed -i '' -e 's/置換対象の文字列/置換後の文字列/g'

さいごに

長く書きましたが、次の3つが使えればとりあえず便利です!

  • git grep xxx
    • シンプル版
  • git grep -i yyy
    • 大文字小文字を区別しない版
  • git grep -E zzz
    • 正規表現版

現在の仕事では複数リポジトリを扱っているので、「修正対象はどのリポジトリだっけ?」などを簡単に調査できるため重宝しています。(IDE開いて検索するより簡単)

参考