はじめに

生成AIを使用すれば、初心者でも、非エンジニアでも簡単にアプリケーションが作れるとよく言われます。確かに、IT知識があまりなくとも、AIが技術的な選定とコーディングを実施してくれるため、ある程度のものを作ることができます。しかし、自分の身を守るためのGitの知識は、AIに頼らず自分自身で身につける必要があります。どの操作が危険で、どうすればリスクを回避できるのか、もしも重大なミスを犯してしまった場合、どう対処すればいいのか。これらの守りの策を知らなければ、ミスの怖さが勝ち、AIという便利なツールをストレスなく使い倒すことが難しくなってしまいます。(人によるかもですが、私はそのタイプです。。。。。)そこで、本記事では、最低限知っておくべきGitの「リスク回避策」を紹介します。

Gitの基礎1:リスク回避策を理解するために

まず、この後に紹介するリスク回避策とミスへの対応策のツールを理解するために必要な最低限のGitの基礎知識を説明していきます。タイトルを見て、「こんなの基礎中の基礎で知っているよ」と思われる方は、とばしていただいても構いません。

Gitとは分散型バージョン管理システム

そもそも、Gitは分散型バージョン管理システムです。ここでいうバージョン管理システムとは、一つのプロジェクトにて「誰がどの操作をしたのかの情報とその際のスナップショット」を保存・管理できるシステムのことを指します。加えて、Gitは「分散型」のため、バージョンの情報をローカル環境にコピーし(いわゆるpullにあたります)、開発メンバーはオフラインでプロジェクトの開発を行うことができます。

ローカル環境における3つの作業領域

そして、Gitではローカル環境における変更管理を3つの作業領域によって行います。その3つの領域とは下記です。

  • 作業ディレクトリ:作業を実施するファイル・ディレクトリそのもの
  • ステージングエリア:リポジトリに登録する対象を一時的に置いておく場所
  • リポジトリ:誰がどの操作をしたのかの情報やその際のスナップショットが保存された場所

まず「作業ディレクトリ」でファイルやフォルダの操作を行う。ある程度作業にキリがついたら、リポジトリに保存したい対象は「ステージングエリア」に追加(git add)する。その後、「ステージングエリア」に追加されたファイルやディレクトリが変更履歴として保存されても問題ないことが確認できれば、リポジトリに登録(git commit)する。これがGitのローカル環境における変更管理の一連の流れです。

1度リポジトリに登録されたファイルやディレクトリはGitに追跡される。

先ほど、Gitでは3つの作業領域によって変更管理が行われることを説明しました。そして、この最終段階にあたるリポジトリに登録されたファイルやディレクトリは、その後、Gitによって追跡されます。Gitによって追跡されたファイルは、今後、git commitによってスナップショットが保存される際、自動的にスナップショットに含められます。具体的にイメージしにくいですね。もう少しわかりやすく補足します。

例えば、cat.pydog.pyという2つのファイルをGitで管理している場合を想定してください。

作業ディレクトリ
- cat.py
- dog.py

この場合に下記のGit操作が行われた場合、2回目のcommitでリポジトリに登録されたスナップショットにcat.pyは含まれるでしょうか?

1|git add . ですべてのファイルをステージングエリアに追加する。
2|git commit で(1)でステージングエリアに追加したファイルをリポジトリに登録する。
3|git add dog.py でdog.pyのみステージングエリアに追加する。
4|git commit で(2)でステージングエリアに追加したファイルをリポジトリに登録する。

結論、この場合、cat.pyもスナップショットに含まれます。スナップショットには、(4)で更新したdog.pyと(2)で一度commitした時点でのcat.pyの情報が履歴として残されます。どうして、cat.pyも含まれるのか?それは明示的に削除しない限り、一度commitされたファイルはステージングエリアに残り続けるためです。そして、この残り続けている状態を、Gitによって追跡されているといいます。

まとめ

以上、これから紹介するGitのリスク回避方法を理解するための基礎知識をまとめました。

  • Gitを使うとローカル環境も利用しながら、プロジェクトの「誰がどの操作をしたのかの情報とその際のスナップショット」を保存・管理できる。
  • ローカル環境では、「作業ディレクトリ」、「ステージングエリア」、「リポジトリ」の3つの領域で、バージョン管理を行う。
  • Gitに追跡されている状態とは、リポジトリに登録され、ステージングエリアに残っている状態のことを示す。

この章でお伝えしたかったのはこの3つです。そして、これから説明するのは、機密情報など公開されてはいけない情報を「リポジトリに登録しないための方法」と「ステージングエリアに追加しない、つまり、 Gitに追跡させない方法」です。

リスク回避策

AI駆動開発をしているとコミットされるファイルやフォルダを全て把握するのはほぼ不可能

git commitでリポジトリに登録されたファイルやフォルダは、git pushでリモートリポジトリに登録されると、チームメンバーの作業ディレクトリに影響を及ぼします。また、それがパブリックなリモートリポジトリの場合、インターネット上の誰もがフォルダやファイルの中身にアクセスできてしまいます。そのため、私たちは、環境を汚すファイルやアクセスキーなどのクレデンシャル情報をcommitしていないか、慎重に確認する必要があります。しかし、これは初心者エンジニアである私がAI駆動開発に1ヶ月ほど取り組んだ所感ですが、AI駆動開発をしていると全てのファイルの中身を把握するのは困難です。そのため、「git-secrets」と「.gitignore」を通じて、事故を防ぐ仕組みを作ろうというのが今回のお話です。

git-secrets ~ リポジトリに登録しないための方法 ~

git-secretsとは

git-secretsとはコミットの際、ユーザーが事前に指定した文字列が追跡されたファイルやフォルダに含まれていないかを自動的に検出するツールです。言葉で説明するより、事例を見たほうが早いので下記のコマンド結果を見てください。

pppp-pp@ppp-pppp git-secrets-test % git add .
pppp-pp@ppp-pppp git-secrets-test % git commit -m "test error"
test.txt:1:BACKLOG-API-KEY = "*********"
test.txt:2:AWS-ACCESS-KEY-ID = "*********"

[ERROR] Matched one or more prohibited patterns

Possible mitigations:
- Mark false positives as allowed using: git config --add secrets.allowed ...
- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
- List your configured patterns: git config --get-all secrets.patterns
- List your configured allowed patterns: git config --get-all secrets.allowed
- List your configured allowed patterns in .gitallowed at repository's root directory
- Use --no-verify if this is a one-time false positive
pppp-pp@ppp-pppp git-secrets-test %

このコマンド結果は事前にgit-secretsをインストールした上で、「~KEY = ~」という文字列が含まれるものとAWSの機密情報を検知するように設定したものです。

実際、リポジトリに登録しようとしていたファイルの中には下記のようにSaasアプリのAPIキーとAWSのアクセスキーを記載していました。

#test.txt
BACKLOG-API-KEY = "*********"
AWS-ACCESS-KEY-ID = "*********"

このように、git-secretsで「機密情報が記載される可能性がある文字列」を登録しておくと、リポジトリの登録される前に、自動的にcommitを拒否してくれます。

検出パターンの登録方法

次に、検出パターンの登録方法について説明します。

※インストール方法は公式ドキュメントに記載されているので、ここでは詳しく触れません。下記のドキュメントを参照にインストールすることができます。
参照:git-secrets を使用して Git リポジトリに機密情報やセキュリティ上の問題がないかスキャンする

既定パターンの登録(AWS)

AWSのアクセスキー等の標準的な形式を監視対象に加える場合は、ユーザー側が規定パターンをそのまま適用することができます。(そもそも、git-secretsはawsによって公式で提供されているサービスです。)

# 全プロジェクトにAWS用の監視パターンを適用
git secrets --register-aws --global
独自パターンの登録

例示したBACKLOG-API-KEYのようなAWS以外のクレデンシャル情報も、git secrets –addによる独自パターンの登録で検出できます。ちなみに、独自パターンの設定には正規表現を用います。ここでは、正規表現については生成AIの壁打ちや検索で理解することができるので、詳しく説明しません。但し、これだけ覚えておきたいのですが、正規表現と言っても系統によって書き方が異なります。git secrets –addで使用される系統はegrep互換の拡張正規表現(ERE)であり、macOSを使用している場合は、そのBSD版です。この情報を前提に、生成AIと壁打ちすると、自分が意図する検出パターンを作成することができると思います。

# 「~KEY~ = "値"」という形式を検知するパターンを登録
git secrets --add '.*KEY[[:space:]]*=[[:space:]]*".+"'

上記例の正規表現
.:何かしらの文字
*:1つ前の文字が0個以上
KEY:KEYという文字列
[[:space:]]:スペース

git secrets –scanで確認する。

ここまで検出パターンの登録方法を説明しましたが、意図する通りの挙動なのかを確認できた方がより安心です。その確認のために便利なコマンドオプションとして、git secrets --scanを紹介します。git secrets --scanを使用すると、commitする前に全てのファイルをスキャンし、検出することができます。例えば、本当にAWSのアクセスキーと「~KEY~ = “値”」を検出できるか否かを下記のように検証できます。

<br />#テスト用のファイルを作成する。
pppp-pp@ppp-pppp % git-secrets-test % touch test.txt

#テストしたいクレデンシャルをテスト用ファイルに記載する。
pppp-pp@ppp-pppp % git-secrets-test % echo 'AWS-ACCESS-KEY-ID = "AKIADUMMY12345678910"' > test.txt
pppp-pp@ppp-pppp % git-secrets-test % echo 'BACKLOG-API-KEY = "******************"' >> test.txt

# スキャンする。
pppp-pp@ppp-pppp % git secrets --scan
test.txt:1:AWS-ACCESS-KEY-ID = "AKIADUMMY12345678910"
test.txt:2:BACKLOG-API-KEY = "******************"

[ERROR] Matched one or more prohibited patterns

Possible mitigations:
- Mark false positives as allowed using: git config --add secrets.allowed ...
- Mark false positives as allowed by adding regular expressions to .gitallowed at repository's root directory
- List your configured patterns: git config --get-all secrets.patterns
- List your configured allowed patterns: git config --get-all secrets.allowed
- List your configured allowed patterns in .gitallowed at repository's root directory
- Use --no-verify if this is a one-time false positive

# エラーを確認できたため、テスト用のファイルを削除する。
pppp-pp@ppp-pppp rm test.txt

以上、git-secretsをインストールし、検出パターンを設定することで、危険な情報がcommitされてしまうことを防止することができます。ただ、この方法だとファイルやフォルダ単位でリポジトリに設定しない対象を定めることができません。そこで、次に紹介する「.gitignore」という設定ファイルを活用する必要があります。

.gitignore ~ 追跡しないファイルやフォルダを設定する ~

.gitignoreとは

.gitignoreとは、Gitが追跡しないファイルやディレクトリを指定するための設定ファイルです。つまり、最初に触れた「追跡」の説明も踏まえると、.gitignoreによって、git add .でステージングエリアに追加されず、commit でスナップショットを取得する対象から外れるファイルやフォルダを設定することができます。

.gitignoreの使い方の概要

こちらについても具体例を交えながら、使い方を説明していきます。次の節でも説明しますが、追跡しないファイルやディレクトリの設定・選択自体は生成AIによる作成やテンプレートの活用で十分に対応できます。そのため、ここでは.gitignoreの使用方法の概要を掴むだけで問題ありません。

確認方法:
.gitignoreに設定した.envファイル(と.gitignore)と.gitignoreに設定しないtest.txtの挙動を、git statusgit ls-files --stageの2つのコマンドで確認する。

git status:作業ディレクトリのステータスを表示するコマンド。例えば、git addでステージングエリアに追加されているが、git commitでリポジトリに登録されていないファイルや、作業ディレクトリで編集・変更・削除されているが、まだgit addでステージングエリアに追加されていないファイルの一覧を表示する。
git ls-files --stage:ステージングエリアに登録されているファイルの詳細情報を表示するコマンド。

1|検証準備
まず、gitを初期化設定したフォルダを用意し、その中に、test.txt.gitignoreと.envを作成します。

フォルダの準備

pppp-pp@ppp-pppp Projects % mkdir git-gitignore-test
pppp-pp@ppp-pppp Projects % cd git-gitignore-test
pppp-pp@ppp-pppp git-gitignore-test % git init
Initialized empty Git repository in /Users/pppp-pp/Projects/git-gitignore-test/.git/

ファイルの準備

pppp-pp@ppp-pppp git-gitignore-test % touch test.txt
pppp-pp@ppp-pppp git-gitignore-test % touch .gitignore
pppp-pp@ppp-pppp git-gitignore-test % touch .env
pppp-pp@ppp-pppp git-gitignore-test %

この段階で念のため、git statusで作業ディレクトリの状態を確認します。

pppp-pp@ppp-pppp git-gitignore-test % git status
On branch main

No commits yet

Untracked files:
(use "git add ..." to include in what will be committed)
.env
.gitignore
test.txt

nothing added to commit but untracked files present (use "git add" to track)
pppp-pp@ppp-pppp git-gitignore-test %

見ていただいたらわかる通り、新規作成したファイルはUntracked files:、つまり、追跡されていないファイルとして表示されています。そして、追跡されていないということは、git ls-files --stageで確認できる通り、ステージングエリアに追加されていないということです。

pppp-pp@ppp-pppp git-gitignore-test % git ls-files --stage
pppp-pp@ppp-pppp git-gitignore-test %

2|.gitignoreに登録して、ステージングエリアに追加する。
次に、.gitignoreに.env​(と.gitignore​)のみ追記し、保存します。

そして、git-gitignore-testフォルダに作成したファイルをすべてステージングエリアに追加するgit addコマンドを入力します。

pppp-pp@ppp-pppp git-gitignore-test % git add .

git add .を入力したものの.gitignoreに追記したファイルはステージングエリアに追加されていないはずです。git statusgit ls-files --stageで確認してみます。

pppp-pp@ppp-pppp git-gitignore-test % git status
On branch main

No commits yet

Changes to be committed:
(use "git rm --cached ..." to unstage)
new file: test.txt

pppp-pp@ppp-pppp git-gitignore-test %
pppp-pp@ppp-pppp git-gitignore-test % git ls-files --stage
100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 test.txt
pppp-pp@ppp-pppp git-gitignore-test %

先にパッと見でわかりやすいgit ls-files --stageから見てみると、ステージングエリアにtest.txtのみが登録され、.gitignoreに追記した.env.gitignoreはステージングエリアに追加されていません。また、git statusに関しても、Untracked files:といった明示的な表示はありませんが、.gitignoreに追記していないtext.txtのみ、Changes to be committed(意訳:コミットする変更対象)に含まれていることがわかります。

以上より、.gitignoreを活用すると、追跡しないファイル、つまり、ステージングエリアに追加したくないファイルを指定することができます。しかし、.gitignoreを活用する上で重要な注意点が一つあります。それは、一度、ステージングエリアに追加されたファイルやフォルダは、その登録を解除する必要があるという点です。

追跡済みのファイルやフォルダはgit rm --cachedで追跡解除をする必要がある。

最初に追跡の概念を説明した際、1度リポジトリに登録されたファイルやディレクトリはGitに追跡され、明示的に削除しない限り、一度commitされたファイルはステージングエリアに残り続けると言及しました。そして、gitignoreではgit addした際に新たにステージングエリアに追加しないファイルやフォルダを指定することはできますが、既に追加されたファイルやフォルダを削除することはできません。そのため、一度、git addでステージングエリアに登録した、もしくは、git commitでリポジトリに登録したファイルやフォルダはgit rm --cachedで追跡状態、つまり、自動的にステージングエリアに登録された状態を解除する必要があります。

例えば、先ほどの検証の続きで、test.txtをリポジトリに登録したとしましょう。

pppp-pp@ppp-pppp git-gitignore-test % git commit -m 'testをコミットする'

この場合、後から.gitignoretest.txtを追記しても、一度、リポジトリに登録されたファイルやフォルダは自動的にGitによって追跡されるため、test.txtはステージングエリアに含まれます。

pppp-pp@ppp-pppp git-gitignore-test % git ls-files --stage
100644 37b72b40ab5a334a8ffe492cc9ae0bf014c8d5bd 0 test.txt
pppp-pp@ppp-pppp git-gitignore-test %

そのため、明示的にgit rm --cached ファイル名で、追跡を解除する必要があるのです。

pppp-pp@ppp-pppp git-gitignore-test % git rm --cached test.txt
rm 'test.txt'
pppp-pp@ppp-pppp git-gitignore-test %

AI駆動型開発をする際の実践的な使い方

ここまで.gitignoreの概要を簡単なフォルダ構成のファイルを例に説明してきましたが、実際の開発では、複数のフォルダやファイルで構成された複雑なプロジェクトで活用する必要があります。それらの追跡しないファイルやフォルダを一つ一つ追加しないといけないと考えると気が遠くなりますね。。。しかし、これに関してはファイルやディレクトリを参照できるAI(Claude CodeやKiroなど)なら、ある程度任しても問題ないと思われます。※1

プロンプトの例:

❯ これから現状の作業ディレクトリをgit commitでリポジトリに登録したいと考えています。チームの環境を汚すファイル・フォルダや、アクセスキーなどのセキュリティに問題があるファイル・フォルダを追跡しないように.gitignoreに追記してください。

また、もし、AIに任せすぎるのが不安であれば、gitignore.ioというサイトから自動生成することができます。
このサイトにて、使用する言語・フレームワーク・OS・ツールを入力画面に記入し、「作成する」を選択すると、それに適した.gitignoreのコードが自動で生成されます。

※1AIに任せても良いと考える理由は.gitignoreに保存するべきファイルはある程度言語やフレームワークごとにある程度テンプレート化されているためです。実際、この後に説明している.gitignoreというgitignore.ioから.gitignoreの中身を自動生成することができます。また、Claude CodeのようなAIはプロジェクト配下のファイルやフォルダをコンテキストとして読み込むことが得意です。そのため、ClaudeCodeなどのAIを使用していた場合、AI自身がファイルやフォルダの構成から使用される言語やフレームワーク、開発環境を自律的に調査し、それに適した.gitignoreへの設定対象を一般的なテンプレートから選択してくれるのではないかと考えています。(あくまで初心者の個人的意見です。)

最後に

以上、生成AIを使って開発する上で初心者エンジニアが知っておきたいGitのリスク回避策を紹介しました。「ファイルの中身という単位」でリポジトリに登録したくない記述を検出するためにgit secretsを、「ファイルやフォルダという単位」でリポジトリに登録したくない対象を指定するためにgitignoreを 使用することで、Gitのリスクを大幅に削減することができます。セキュリティ事故の事後対応には数千万円以上のコストがかかるという調査結果がある一方で、AIを活用すれば初心者でもこれらの設定はわずか数分で行えます。万が一に備えるこれらの安全装置を使いこなし、ストレスのない快適なAI駆動開発を楽しみましょう。