PullRequest の特定フォルダー内のファイル差分だけをコマンドで取得したい！

# PullRequest の特定フォルダー内のファイル差分だけをコマンドで取得したい！

指定したフォルダーに差分があるときだけ、ビルド・テスト・デプロイを行う GitHub Actions を作りたい！

そんな状況になることがあると思います！

この問題を解決するために、ブランチのファイル差分を取得するスクリプトを調べてみました。

最終的にでき上がったスクリプトはこちらです！

```bash
# ブランチ根本コミット取得する
baseCommit=$( \
  { diff -u <(git rev-list --first-parent ${BRANCH_NAME}) <(git rev-list --first-parent ${TARGET_BRANCH}) || true; } | \
  sed -ne 's/^ //p' | \
  head -1 \
)

# ブランチ先端コミット取得する
headCommit=`git rev-parse ${BRANCH_NAME}`

# コミットを比較し、ファイル差分を取得する
git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY}
```

- `BRANCH_NAME` はプルリクエストのブランチです。

- `TARGET_BRANCH` はプルリクエストのマージ先のブランチです。
- `DIRECTORY` は指定したいディレクトリです。

こちらのスクリプトを解説します。

# ブランチ根本コミットを取得するコマンド

以下のコマンドを実行すると、ブランチの分岐元コミットを調べることができます。

```bash
baseCommit=$( \
  { diff -u <(git rev-list --first-parent ${BRANCH_NAME}) <(git rev-list --first-parent ${TARGET_BRANCH}) || true; } | \
  sed -ne 's/^ //p' | \
  head -1 \
)
```

段階を分けて解説します。

まず、 `git rev-list` で、指定したブランチのコミットログを取得できます。こんな感じです。

```bash
$ git rev-list --first-parent origin/${BRANCH_NAME}

62d58bf10bd6dd391142311de5f0122fcc13669a
4336e8bed15c4c991703abe67769562c9ea8d9fa
c56fc286b45c61d00e3616c619555fbb21bce95a
108f8ebbf6233ae2d63d088c620611f5b1bb4daa
71b752b3aed0d6ec8b73fe620eb343cad3af469a
```

※上記のコミットハッシュ値は架空のものです。

次に、 `diff` コマンドで、コミットログ同士を比較しています。

終了コードがエラーになることがあり、GitHubActions で利用する際に困るので、 `true` で終了するようにしています。

```bash
$ { diff -u <(〇〇〇) <(〇〇〇) || true; }

--- /dev/fd/63  2022-04-15 16:49:28.000000000 +0900
+++ /dev/fd/62  2022-04-15 16:49:28.000000000 +0900
@@ -1,4 +1,4 @@
+fddb596c92b46d87dae58969c6b9aa0881a17bda
 4336e8bed15c4c991703abe67769562c9ea8d9fa
 c56fc286b45c61d00e3616c619555fbb21bce95a
 108f8ebbf6233ae2d63d088c620611f5b1bb4daa
```

次に、 `sed` コマンドで、 で始まる行 （= `+` `-` `@` で始まらない行） を抽出します。

これにより、2 つのブランチの共通コミットの一覧を取得できます。以下のイメージです。

```bash
$ 〇〇〇 | sed -ne 's/^ //p'

4336e8bed15c4c991703abe67769562c9ea8d9fa
c56fc286b45c61d00e3616c619555fbb21bce95a
108f8ebbf6233ae2d63d088c620611f5b1bb4daa
```

最後に、 `head` コマンドで、共通コミット一覧の中から一番上のものを取得します。
これを 2 つのブランチの分岐点（＝ PR ブランチの根本）とみなします。

```
$ 〇〇〇 | head -1

4336e8bed15c4c991703abe67769562c9ea8d9fe
```

これで、ブランチの分岐元コミットを調べることができました！

# ブランチ先端コミットを取得するコマンド

以下のコマンドを実行すると、最新コミットのハッシュを取得できます。

```bash
headCommit=`git rev-parse ${BRANCH_NAME}`
```

# 2 つのコミットのファイル差分を取得するコマンド

以下のコマンドを実行すると、2 つのコミットのファイル差分をリストで取得できます。

```bash
git diff ${headCommit} ${baseCommit} --name-only
```

# 特定フォルダーにおける 2 つのコミットのファイル差分を取得するコマンド

上記のコマンドに `relative` オプションを加えると、特定フォルダーに関するものだけリスト化できます！

```bash
git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY}
```

# おまけ: ファイル差分の数をカウントするコマンド

以下のようにすれば、ファイル差分の数をカウントできます！

```bash
count=$( \
  git diff ${headCommit} ${baseCommit} --name-only --relative=${DIRECTORY} | \
  wc -l \
)
```

この `${count}` が 0 ならファイル差分はなし、1 以上ならファイル差分はありだと判断できます！

GitHub Actions の条件式に組み込めば、指定したフォルダー￥に差分があるときだけ、ビルド・テスト・デプロイを行う GitHub Actions を作ることができます！

# さいごに

本記事作成にあたり、以下の記事を参考にしました。ありがとうございました。

- [github actions を使って特定のディレクトリに差分があるときにテストを行う](https://qiita.com/ningenMe/items/e2ed82c9c740ad10d480)
- [stack overflow / Finding a branch point with Git?](https://stackoverflow.com/questions/1527234/finding-a-branch-point-with-git)