Terraform や CloudFormation を CI/CD で回していると、Git は「コードを保存する道具」ではなく 変更を本番に届ける入口 になります。 この記事では、インフラエンジニアが日常的に使うコマンドを、実際の出力例つき で運用の流れに沿って並べます。後半では設定とセキュリティ(名乗り・秘密情報の除外・誤コミットに気づく仕組み)も扱います。

各コードブロックの上に Command(入力するもの)と Output(表示される結果)の見出しを付けています。 出力例のブランチ名・ハッシュ・ファイル名・人名・日付は説明用の架空のものです。

全体の流れ#

main を最新にする → future- / fix- ブランチを作る → IaC を修正
  → status/diff で確認 → add → commit → push → PR
  → (CI で plan を確認) → main にマージ → CI が apply
  → ローカルの main を pull して終わり

main に直接 push しない のが前提です。変更は必ず作業ブランチで行い、PR とレビュー、CI の plan を通してから main に入れます。

ブランチ名の命名ルール#

作業ブランチの名前は、目的を表す接頭辞 + 内容 にします。

接頭辞使う場面例
future-新しいリソースや設定の追加future-add-sg-rule、future-rds-backup
fix-既存の設定の修正、不具合の修正fix-alb-healthcheck、fix-sg-cidr

接頭辞で揃えておくと、git branch の一覧や PR の一覧で「追加なのか修正なのか」がひと目で分かります。

1. 作業を始める#

最新の main から future- ブランチを切る#

Command

git switch main

Output

Switched to branch 'main'
Your branch is up to date with 'origin/main'.

Command

git pull

Output

Already up to date.

Command

git switch -c future-add-sg-rule

Output

Switched to a new branch 'future-add-sg-rule'
  • git switch -c <名前> は「ブランチを作って移動」です。修正なら fix-<内容> で切ります。
  • 注釈: git checkout -b <名前> でも同じ結果になります。switch は Git 2.23(2019 年)で追加されたコマンドで、ブランチの切り替え専用です。checkout はファイルの復元にも使われて紛らわしいため、この記事では switch に統一しています。古い Git や、ほかの手順書では checkout -b が使われている場合があります。
  • 古い main から切ると、あとでマージ時に衝突しやすくなります。切る前に必ず pull します。

2. 状態を確認する: git status#

Command

git status

Output

On branch future-add-sg-rule
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
        modified:   modules/network/security_group.tf
        modified:   envs/prod/terraform.tfvars

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        notes.txt

見るべきは 3 つの区分です。

区分意味
Changes to be committedadd 済み。次の commit に入る
Changes not staged for commit変更済みだが add していない
Untracked filesGit がまだ知らない新規ファイル

短く見たいときは -s が便利です。

Command

git status -s

Output

 M envs/prod/terraform.tfvars
 M modules/network/security_group.tf
?? notes.txt

左の列が add 済み、右の列が未 add の状態です。?? は未追跡を表します。

3. 変更を確認する: git diff#

add する前に、自分が何を変えたか を必ず目で確認します。

Command

git diff                      # まだ add していない変更
git diff --staged             # add 済み(次の commit に入る)変更

ファイルを指定すると、そのファイルの変更だけを見られます。

Command

git diff modules/network/security_group.tf

Output

diff --git a/modules/network/security_group.tf b/modules/network/security_group.tf
index 3f2a1b0..8c4d9e7 100644
--- a/modules/network/security_group.tf
+++ b/modules/network/security_group.tf
@@ -12,6 +12,13 @@ resource "aws_security_group" "app" {
     cidr_blocks = ["10.0.0.0/16"]
   }

+  ingress {
+    from_port   = 8443
+    to_port     = 8443
+    protocol    = "tcp"
+    cidr_blocks = ["10.0.0.0/16"]
+  }
+
   egress {

+ が追加、- が削除です。IaC では 0.0.0.0/0 の混入や、環境違い(prod/dev)の取り違え をここで見つけます。

4. ステージする: git add#

変更対象だけを追加する#

git add . や git add -A は すべて を入れてしまいます。上の例の notes.txt のような関係ないファイルや、ローカルの一時ファイルが混ざる原因になります。 ファイルを指定して追加する 習慣をつけます。

Command

git add modules/network/security_group.tf envs/prod/terraform.tfvars

git add は成功しても何も表示しません。結果は status で確かめます。

Command

git status -s

Output

M  envs/prod/terraform.tfvars
M  modules/network/security_group.tf
?? notes.txt

左の列に M が付いたのが add 済みです。notes.txt は入っていません。

ファイルの一部だけ追加する: git add -p#

1 つのファイルに、別々の目的の変更が混ざっているときは、塊(hunk)ごとに選べます。

Command

git add -p modules/network/security_group.tf

Output (interactive)

@@ -12,6 +12,13 @@ resource "aws_security_group" "app" {
...
(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? y

y で追加、n で見送り、s でさらに細かく分割、e で手で編集できます。

間違えて add したときの取り消し#

Command

git restore --staged notes.txt

成功しても何も表示しません。ステージから外すだけで、ファイルの中身は消えません。

5. コミットする: git commit#

Command

git commit -m "app 用 SG に 8443/tcp の ingress を追加"

Output

[future-add-sg-rule 5d1e8a2] app 用 SG に 8443/tcp の ingress を追加
 2 files changed, 8 insertions(+), 1 deletion(-)

コミットメッセージの書き方のポイント#

IaC のコミット履歴は、障害のときに「いつ・何を・なぜ変えたか」を追う手がかり になります。

  1. 1 行目は「何をしたか」を短く、具体的に。 「修正」「更新」だけにしない
  2. 対象を入れる。 どのリソース・どの環境かが分かるようにする(例: prod、app 用 SG)
  3. 1 コミット 1 目的。 無関係な変更を混ぜない(混ぜると戻すときに困る)
  4. 「なぜ」は本文に書く。 1 行目のあとに空行を入れ、理由・影響・チケット番号を書く
  5. 破壊的な変更は明記する。 リソースの作り直し(replace)や削除が発生するなら必ず書く

-m を付けずに実行すると、エディタが開きます。

Command

git commit

Editor (commit message)

app 用 SG に 8443/tcp の ingress を追加

新しい管理 API が 8443 で待ち受けるため。
VPC 内(10.0.0.0/16)からのみ許可。既存ルールは変更なし。
plan の結果: 1 to add, 0 to change, 0 to destroy
Refs: INFRA-123

悪い例と良い例です。

悪い例良い例
fixprod の ALB ヘルスチェック間隔を 30 秒から 10 秒に変更
update tfRDS のバックアップ保持期間を 7 日から 14 日に延長
いろいろ修正(目的ごとに分けて 3 コミットにする)

直前のコミットのメッセージを直したいときは、push する前なら git commit --amend が使えます。push 済みのものを書き換えるのは避けます。

6. 送る: git push#

Command

git push -u origin future-add-sg-rule

Output

Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Writing objects: 100% (5/5), 612 bytes | 612.00 KiB/s, done.
remote: Create a pull request for 'future-add-sg-rule' on GitHub by visiting:
remote:      https://github.com/example/infra/pull/new/future-add-sg-rule
To github.com:example/infra.git
 * [new branch]      future-add-sg-rule -> future-add-sg-rule
branch 'future-add-sg-rule' set up to track 'origin/future-add-sg-rule'.
  • -u は初回だけ。以降は git push だけで送れます。
  • 出力に PR 作成用の URL が出ます。gh pr create でも作れます。

Command

gh pr create --fill

PR を出すと CI が terraform plan などを走らせ、差分が PR に表示されます。plan の結果を確認してからマージ します。

7. マージして取り込む#

PR をマージする#

Command

gh pr merge --squash --delete-branch

squash は、ブランチ内の複数コミットを 1 つにまとめて main に入れます。履歴が読みやすくなります。マージされると CI が apply を実行します。

ローカルに反映する: git pull#

Command

git switch main
git pull

Output (git pull)

Updating 2a9c4f1..7b3e6d0
Fast-forward
 envs/prod/terraform.tfvars          | 1 +
 modules/network/security_group.tf   | 7 +++++++
 2 files changed, 8 insertions(+)

作業ブランチ上で「他の人が main に入れた変更」を取り込みたいときは、main の最新を取ってきてマージします。

Command

git fetch origin
git merge origin/main

git pull は fetch と merge を 1 度にやるコマンドです。何が来るかを先に見たい ときは fetch だけ実行して、git log HEAD..origin/main で確認できます。

衝突(コンフリクト)したら#

Output (git merge origin/main — conflict)

Auto-merging modules/network/security_group.tf
CONFLICT (content): Merge conflict in modules/network/security_group.tf
Automatic merge failed; fix conflicts and then commit the result.

ファイルの <<<<<<< ======= >>>>>>> で囲まれた部分を直し、add して commit で完了します。やめたいときは git merge --abort です。

古いブランチを片付ける#

Command

git branch -d future-add-sg-rule
git fetch --prune

8. 履歴を調べる#

グラフで全体を見る#

Command

git log --oneline --graph --decorate --all

Output

* 7b3e6d0 (HEAD -> main, origin/main) app 用 SG に 8443/tcp の ingress を追加
* 2a9c4f1 prod の ALB ヘルスチェック間隔を 10 秒に変更
| * c8d0e12 (origin/future-rds-backup) RDS のバックアップ保持を 14 日に延長
|/
* 91fb3a7 dev 環境の NAT Gateway を 1 台に削減
* 4e6a0b5 VPC モジュールを v2 に更新

分岐とマージが見えるので、「どのブランチがどこから分かれたか」「どこまで main に入ったか」が一目で分かります。

一覧を絞る#

Command

git log --oneline -10                      # 直近 10 件
git log --oneline -- modules/network/      # このディレクトリに触れたものだけ
git log --since="2 weeks ago" --oneline    # 期間で絞る
git log --stat -3                          # 変更ファイルと行数つき

誰が変えたかを探す#

人で絞るときは --author を使います。

Command

git log --author="sato" --oneline

行ごとに最終変更者を見るときは blame です。

Command

git blame modules/network/security_group.tf

Output (excerpt)

^4e6a0b5 (Yamada 2026-09-02 10:12:41 +0900 11)     cidr_blocks = ["10.0.0.0/16"]
5d1e8a2a (Sato   2026-10-25 09:30:05 +0900 15)     from_port   = 8443

git blame の各行には、その行を最後に変えたコミット・人・日時 が出ます。気になる行のコミットは、次のコマンドで詳細を見ます。

Command

git show 5d1e8a2

文字列の入った変更を探す(ピッケル検索)#

「0.0.0.0/0 はいつ入ったのか」「あの変数はいつ消えたのか」を探すときに強力です。

Command

git log -S"0.0.0.0/0" --oneline

Output

d41c7e9 検証用に SSH を全開放
3a8f5b2 SSH の許可元を社内 CIDR に限定

-S は「その文字列の出現数が増減したコミット」を出します。

過去のコミットと比較する: git diff#

Command

git diff HEAD~1                       # 1 つ前のコミットと現在
git diff 2a9c4f1 7b3e6d0              # 2 つのコミットの差分
git diff main future-rds-backup       # ブランチ同士の差分
git diff 2a9c4f1 7b3e6d0 --stat       # 変更ファイルの一覧だけ
git diff 2a9c4f1 7b3e6d0 -- modules/network/security_group.tf   # 1 ファイルだけ

Output (git diff 2a9c4f1 7b3e6d0 --stat)

 envs/prod/terraform.tfvars        | 1 +
 modules/network/security_group.tf | 7 +++++++
 2 files changed, 8 insertions(+)

main...future-xxx(ドット 3 つ)にすると、「分岐してからブランチ側で増えた分」だけを見られます。PR の差分と同じ見え方です。

過去のコードを確認する#

作業ツリーを変えずに、過去の時点のファイルの中身だけ を見るなら show です。

Command

git show 91fb3a7:modules/network/nat.tf

その時点のプロジェクト全体を見たいときは、チェックアウトします。

Command

git switch --detach 91fb3a7

Output

HEAD is now at 91fb3a7 dev 環境の NAT Gateway を 1 台に削減

この状態は どのブランチにも属していません。見終わったら戻ります。

Command

git switch main

変更を元に戻す#

やりたいことコマンド
未 add の変更を捨てるgit restore <ファイル>
add を取り消すgit restore --staged <ファイル>
公開済みのコミットを打ち消すgit revert <ハッシュ>

main に入ったコミットを戻すときは、履歴を書き換える reset ではなく、打ち消しのコミットを作る revert を使います。CI がそのコミットを検知して、元の状態に apply し直してくれます。

9. 設定: 名乗りの設定#

コミットには「誰が」変更したかが記録されます。初回に設定しておきます。

Command

git config --global user.name "Sato"
git config --global user.email "sato@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase false

確認はこうします。

Command

git config --list --show-origin | grep user

Output

file:/home/sato/.gitconfig    user.name=Sato
file:/home/sato/.gitconfig    user.email=sato@example.com

注意点です。

  • 設定した名前とメールは 履歴に残り、あとから変えられません(公開リポジトリでは誰でも見られます)。
  • GitHub で非公開メールを使っているなら、xxxx+name@users.noreply.github.com を設定すると本物のアドレスを晒さずに済みます。
  • 仕事用と個人用でアドレスを分けたいときは、リポジトリごとに上書きします。

Command

cd ~/work/infra
git config user.email "sato@company.example"   # --global を付けない

10. セキュリティ: 秘密情報を Git に入れない#

IaC のリポジトリは、シークレットを入れやすい場所です。一度コミットすると、あとで消しても履歴に残ります。そして公開リポジトリなら、数分で自動収集の対象になります。

入れてはいけないものの例#

ファイル・内容理由
~/.aws/credentials、アクセスキーAWS を直接操作される
*.tfstate、*.tfstate.backupリソースの値や機密が平文で入る
*.tfvars(秘密を含むもの)パスワードや API キー
.env、*.pem、*.key、id_rsa秘密鍵・環境変数
.terraform/プロバイダのバイナリや状態のキャッシュ

.gitignore で除外する#

リポジトリ直下の .gitignore に書きます。

File: .gitignore

# Terraform
.terraform/
*.tfstate
*.tfstate.*
crash.log
override.tf
override.tf.json
*.auto.tfvars
secrets.tfvars

# AWS / 認証情報
.aws/
credentials
*.pem
*.key
id_rsa*

# 環境変数
.env
.env.*

# エディタ・OS
*.swp
.DS_Store

効いているかは check-ignore で確かめられます。

Command

git check-ignore -v secrets.tfvars

Output

.gitignore:11:secrets.tfvars    secrets.tfvars

何も出なければ、除外されていません。

注意: .gitignore は まだ追跡していないファイル にしか効きません。すでにコミット済みのファイルは、書き足しても無視されません。その場合は追跡だけをやめます。

Command

git rm --cached secrets.tfvars
git commit -m "secrets.tfvars を追跡対象から外す"

ただし、履歴には残っています。実際に漏れたときは、次の節のとおり、鍵の無効化が先です。

全プロジェクト共通の除外: グローバル gitignore#

プロジェクトごとに書き忘れないよう、自分のマシン全体にも設定します。

Command

git config --global core.excludesfile ~/.gitignore_global
printf '.aws/\n.env\n*.pem\n.DS_Store\n' >> ~/.gitignore_global

誤って add する前に気づく仕組み#

(1) add の前に必ず status と diff を見る#

git add . を使わず、ファイルを指定する習慣自体が最大の予防です(4 章)。ステージ済みの中身は次で確認できます。

Command

git diff --staged --name-only

(2) 秘密情報を検知するフックを入れる(pre-commit)#

コミットの瞬間に、自動でスキャンして止めてくれる仕組みです。ここでは gitleaks の例を示します。

Command

pip install pre-commit

リポジトリ直下に .pre-commit-config.yaml を作ります。

File: .pre-commit-config.yaml

repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.18.4
    hooks:
      - id: gitleaks

Command

pre-commit install

以降、秘密らしきものが入ったコミットは失敗します。

Command

git commit -m "provider 設定を追加"

Output

Detect hardcoded secrets.................................................Failed
- hook id: gitleaks
- exit code: 1

Finding:     access_key = "AKIAIOSFODNN7EXAMPLE"
RuleID:      aws-access-token
File:        providers.tf
Line:        4

メッセージのとおり、providers.tf にアクセスキーが直書きされています。コードから消し、環境変数や OIDC(アクセスキーを持たない方式)に切り替えます。

(3) CI でも同じ検査をする#

ローカルのフックは 各自の環境でしか動かず、--no-verify で飛ばせます。PR の CI でも同じ検査を走らせ、最後の砦 にします。

(4) GitHub の Secret scanning / Push protection を有効にする#

リポジトリの Settings → Code security で有効にすると、既知の形式の鍵を含む push を、GitHub 側で拒否します。

もし秘密情報をコミットしてしまったら#

順番が大事です。

  1. まず無効化する。 該当のアクセスキーを即座に削除・ローテーションする(履歴から消すより先)
  2. push 前なら、コミットを取り消す(git reset --soft HEAD~1 で戻して、ファイルを外して再コミット)
  3. push 済みなら、すでに漏れたものとして扱う。履歴の書き換え(git filter-repo など)は後始末であり、無効化の代わりにはならない
  4. CloudTrail などで、その鍵が使われていないかを確認する

付録: 運用で使うコマンド早見表#

目的コマンド
作業ブランチを作るgit switch -c future-<内容> / git switch -c fix-<内容>
状態を見るgit status -s
変更を見るgit diff / git diff --staged
対象だけ addgit add <ファイル> / git add -p
コミットgit commit -m "<何を>"
pushgit push -u origin <ブランチ>
PR 作成・マージgh pr create --fill / gh pr merge --squash --delete-branch
最新を取り込むgit pull / git fetch + git merge origin/main
履歴をグラフで見るgit log --oneline --graph --decorate --all
誰が変えたかgit blame <ファイル> / git log --author=<名前>
文字列が入った変更を探すgit log -S"<文字列>"
過去との差分git diff <A> <B>
過去のファイルを見るgit show <ハッシュ>:<パス>
公開済みの変更を戻すgit revert <ハッシュ>
無視されているか確認git check-ignore -v <ファイル>

まとめ#

  • 変更は future- / fix- ブランチ → PR → マージ → CI が apply の一本道にする
  • add は ファイルを指定 し、前後に status と diff で確認する
  • コミットメッセージは 何を・どこに・なぜ が後から追えるように書く
  • 履歴の調査は log --graph、blame、log -S、diff の 4 つを覚えれば足りる
  • 秘密情報は .gitignore と pre-commit と CI と GitHub の保護 の多重で防ぎ、漏れたら 無効化が先