

### やりたいこと

目的は、ローカルにプルした各種のリポジトリに対して一括で同じ検索ワードをまとめて検索できるようにしテキストファイルとして出力したいです。

### 理想

ある検索ワードを入力したら、ローカルにプルしたリモートリポジトリに対して検索を行い、検索結果を一覧化されたファイルをローカルに出力されるイメージをしています。

以下のようなディレクトリのリストがあった場合に、すべてのリポジトリ（ディレクトリ）に対してコマンドで「git grep
”検索ワード”」を実施し、どのリポジトリで検索したのかなどもテキストファイルに出力できたかや検索されたソースコードの一部を出力されたファイルを一覧化してtextファイルなどに保存したいと考えています。  
初歩的な質問で大変恐縮ですがご教授いただけるとありがたいです。

[code]

    C:¥git/repositories_aaa
    C:¥git/repositories_bbb
    C:¥git/repositories_ccc
    C:¥git/repositories_ddd
    
[/code]


CC BY-SA 4.0
2021-08-19T03:38:30.577
80903
2021-08-20T00:44:33.437
2021-08-19T12:25:39.450
41188
41188
question
git batch-file コマンドプロンプト
windowsバッチで複数のリポジトリを検索したい


「Windows バッチで」とありますが Git が使える環境であれば Git Bash 等をインストール済みでしょうから、Unix
コマンドを使った方が簡単だと思います。

リポジトリが一カ所のフォルダ以下にまとめてあるのであれば、`find` コマンド、`xargs` コマンド、そして `grep`
コマンドを組み合わせて以下のように実行することができます。

[code]

    $ cd /c/git
    $ find . | xargs grep -l "keyword"
    
[/code]

grep の `-l` はファイル名のみを表示するオプションです。

コマンドを実行したディレクトリを起点に、キーワードを含むファイルのパスが一覧表示されるので、どのリポジトリに含まれているのかも判別可能なはずです。  
テキストファイルとして結果を残したければ、そのままリダイレクトで保存してください。


CC BY-SA 4.0
2021-08-19T04:59:43.713
80905
2021-08-19T04:59:43.713
3060
80903
answer


Windows 環境なので PowerShell スクリプトを使う方法も考えられます。

**grep_git_repos.ps1**

[code]

    Param([string]$topdir, [string]$searchWord)
    
    # set encoding to UTF-8
    $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
    
    Get-ChildItem -Recurse -Depth 0 -Force $topdir |
      Where-Object {
        # get git repositories path
        if (Test-Path $_.FullName -PathType Container) {
          git -C $_.FullName rev-parse --is-inside-work-tree 2>&1>$null
          $LASTEXITCODE -eq 0
        }
      } |
      ForEach-Object {
        # git grep for each repository
        Write-Output "Repository: $($_.Name)"
        git -C $_.FullName --no-pager grep -P -i -n --threads 4 -e $searchWord
        echo ""
      }
    
[/code]

`git grep` のオプションは適宜変更してください。

**実行例**

PowerShell スクリプトを実行するために execution policies(実行ポリシー)を変更してください。

[code]

    PS> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
    
[/code]

コマンドプロンプトから PowerShell スクリプトを実行します。第1引数に git
リポジトリが置かれているフォルダを、第2引数に検索ワードを指定します。

[code]

    cmd.exe> dir "C:\git"
     C:\git のディレクトリ
    
    2021/08/19  21:28    <DIR>          .
    2021/08/19  21:28    <DIR>          ..
    2021/08/19  21:20    <DIR>          ccls
    2021/08/19  21:23    <DIR>          eglot
    2021/08/19  21:24    <DIR>          go-mode.el
    2021/08/19  21:26    <DIR>          sshfs
    2021/08/19  21:19    <DIR>          whois
    
    cmd.exe> powershell -File grep_git_repos.ps1 "C:\git" "linux|windows" > .\matched.txt
    cmd.exe> more matched.txt
    Repository: ccls
    CMakeLists.txt:33:# CMake sets MSVC for both MSVC and Clang(Windows)
    CMakeLists.txt:35:  # Common MSVC/Clang(Windows) options
                    :
    
    Repository: eglot
    .github/ISSUE_TEMPLATE/bug_report.md:45:* Operating system:          <!-- (windows/mac osx/linux/don't know -->
    README.md:90:fine on Linux and OSX but in some cases
    README.md:91:[*may not work on Windows*][windows-subprocess-hang].
                   :
    
    Repository: go-mode.el
    AUTHORS:23:Juergen Hoetzel <juergen@archlinux.org>
                   :
    
[/code]


CC BY-SA 4.0
2021-08-19T13:46:41.110
80922
2021-08-19T18:19:16.870
2021-08-19T18:19:16.870
47127
47127
80903
answer


要望の通りWindowsバッチで実現すると以下のようになるでしょう。

  * 対象ディレクトリに対象リポジトリ以外のリポジトリ/フォルダがあったり、そもそも対象ディレクトリが分散されている場合も考えてテキストファイルに対象リポジトリのリストを指定して`FOR`コマンドで処理する  
リストは1行1エントリで、ドライブ名から始まるフルパスで指定する

  * どのリポジトリかを示す情報は、Git Bashの`sed`コマンドを使用して全ての検出した行に付ける  
git grepの結果はフルネームを指定してもリポジトリトップからの相対パスなので、その前にリポジトリのパスを挿入する

  * Git BashのUnixコマンド類フォルダへのパスを追加する(既に組み込まれている場合はその行を使わなければ良い)
  * git grepのオプション/検索パターンを複数(10個まで)指定出来るようにしている(常に指定するならバッチファイルの該当行にあらかじめ組み込む)

[code]

    @ECHO OFF
    IF "%3" == "" (
      @ECHO パラメータが不足しています。
      @ECHO 使い方: %~n0  対象リポジトリリストファイルパス  結果出力ファイルパス  git grepオプション/パターンを1個以上10個以下
      EXIT /B 2
    )
    IF NOT EXIST "%~1" (
      @ECHO 対象リポジトリリストファイルが存在していません。
      EXIT /B 1
    )
    SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
    SET PATH=C:\Program Files\Git\usr\bin;%PATH%
    SET TARGETREPOLIST=%~1
    SET OUTPUTPATH="%~2"
    SHIFT
    SHIFT
    SHIFT
    SET GREPARGS=%0 %1 %2 %3 %4 %5 %6 %7 %8 %9
    PUSHD
    FOR /F %%E in (%TARGETREPOLIST%) do (
        CALL :REPOGREP %%E
    )
    POPD
    EXIT /B 0
    
    :REPOGREP
    CD /D "%~1"
    @ECHO ==========  "%~1"  処理中  ==========
    SET REPODIR=%~1
    SET REPODIR=%REPODIR:\=\/%
    git grep %GREPARGS% | sed -e "/^-*$/!s/^/%REPODIR%\//" >>%OUTPUTPATH%
    EXIT /B 0
    
[/code]

* * *

対象リポジトリをテキストファイルではなく、指定したディレクトリ以下全てとする場合は：

[code]

    FOR /F %%E in (%TARGETREPOLIST%) do (
    
[/code]

の部分を以下にすれば良いでしょう。

[code]

    FOR /D %%E in (%TARGETREPOLIST%\*) do (
    
[/code]

* * *

どのリポジトリかを示す情報を、全ての行に付けるのではなく出力結果に区切りの行として入れる形にする場合は：

[code]

    SET REPODIR=%~1
    SET REPODIR=%REPODIR:\=\/%
    git grep %GREPARGS% | sed -e "/^-*$/!s/^/%REPODIR%\//" >>%OUTPUTPATH%
    
[/code]

の部分を以下にすれば良いでしょう。

[code]

    @ECHO ==========  "%~1"  ==========>>%OUTPUTPATH%
    git grep %GREPARGS% >>%OUTPUTPATH%
    
[/code]

* * *

必要なり要望なりに応じて適宜変更してください。


CC BY-SA 4.0
2021-08-20T00:44:33.437
80929
2021-08-20T00:44:33.437
26370
80903
answer