機密情報をGitHubに上げちゃった人は、git rebaseを使ってコミット履歴を書き換えよう！という話

# はじめに結論

`.env.example`などに機密情報を載せたままGitHubに`push`してしまった人は、`git`の`commit`履歴を **`git rebase`** で改変して、GitHubに強制`push`しよう！

# この記事を読むと…

- GitHubに機密情報を`push`しちゃった人がその後すべきことがわかる
- `git rebase` の練習ができる

# 私の場合の経緯

`git rebase`の練習だけやってみたい人は、飛ばしていただいて問題ありません！
私と同じ状況に陥っている方や、セキュリティ意識を高めたい方は、ぜひご一読ください。

私は現在、プログラミング学習とポートフォリオ作成を兼ねて、Laravelを用いた基本的なCRUDアプリを個人開発中の身です。

今回は、開発の序盤も序盤。
ユーザ登録時のメール認証が動作しているかを試すために、Mailtrapというツールを使うことにしました。

## `.env.example` とは

Mailtrap接続のための情報は、`.env`に入れる必要があります。
これを他の環境でもすぐに使えるように、 **`.env.example`** を作成しました。

`env.example`というのは、`.env`に書くべき環境変数をまとめた、`.env`のサンプルとなるファイルです。
環境構築時に、これを`cp .env.example .env`という形でコピーして、必要事項を埋めるだけで、`.env`が完成するので早いよ！というものです。

ただし、 **機密情報は絶対に`.env.example`には載せてはいけません。** 

通常、`.env`は`.gitignore`されており、git管理外となっているので、GitHubには上がりません。よってインターネット上に漏れることはありません。しかし、`.env.example`は、いろんな環境で使ったり、他のメンバーと共有したりするために、git管理するのが前提のファイルです。

これに機密情報を載せてしまい、さらにGitHubリポジトリがPublic設定になっていると、とても危険です。**GitHub 上を巡回している悪意あるクローラー**、つまり情報漏洩を狙う自動巡回プログラムによって、その情報が取得され、**アカウントを不正利用** されてしまう恐れがあります。

Mailtrapくらいなら大きな問題はないかもしれません。しかし、例えば **AWS** との接続情報が漏れていたりすると、マネーロンダリングなどにサーバやストレージを不正利用されてしまうかもしれません。そうすれば、**多額の請求を受ける**といったことになりかねません。

## `.env.example` で伏せるべき情報はパスワードだけではない

Mailtrapに登録する情報は、これだけあります。

```bash
MAIL_MAILER=smtp
MAIL_SCHEME=null
MAIL_HOST=
MAIL_PORT=2525
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tsl
MAIL_FROM_ADDRESS="sample@example.com"
MAIL_FROM_NAME="${APP_NAME}"
```

私は甘いことに、パスワードだけ伏せたら完璧！と思っていました。
しかし、知人エンジニアより指摘を受けました。

**「アカウント名やサービス名、使ってるDBなども、一応隠しておくに越したことはない」** と。

なぜなら、他の情報と合わせて取得されると悪用されるリスクが高まるからです。

あくまでも、**`.env.example`は形式の参考であり、実値は書かない** ということを覚えておきましょう。


私はやってしまいました。
思いっきりアカウント名も書いていました。
そのままGitHubにpushまでしてしまいました。

こうなると、たとえ今から`.env.example`を編集して`commit`して`push`しても、コミット履歴に機密情報が残ったままになってしまいます。

では、これからどうすればいいのでしょうか。

# 機密情報を`push`しちゃった後にやること

## GitHubのリポジトリをPrivateにする

GitHubの該当リポジトリのページから、`setting`タブを開きます。

ページ下部にある`Danger Zone`の、`Change repository visibility`に移動し、`Change Visibility`ボタンから`Private`に変更します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3324036/b61fb8b6-c536-473a-82fe-b1e23a077369.png)



このようにして、悪意あるクロールの対象からいち早く外れましょう。

私の場合は、最初からPrivateにしていたので少し安心でした。
開発中は、不特定多数への公開の必要がないなら、Privateにしておくに越したことはないです。
私は就職活動が始まるまではPrivateのままにしておこうと思っています。

## 機密情報を再発行する

これはリポジトリがPublicになっていた場合だけでよいかもしれません。

`.env.example`に記入した情報はすべて漏れたものと考えて対処するのが安全です。
各サービスのAPIキーやパスワード、ユーザ名など、再発行できるものはすぐに取得しなおしましょう。

その上で、`.env`にその値を設定します。

## `git rebase` でコミット履歴を書き換える

ここで満を持して登場するのが`rebase`です。
過去のコミット履歴を改変することができる、使い方によっては危ないコマンドです。

このことからわかるように、 **本番環境や、共同開発者がいる状況で気軽にやってはいけません。** 
あらゆる人の元でコンフリクト(競合)が発生して大変なことになります。

もし本番で`rebase`で修正しなければならないような重大なミスをしてしまった場合は、速やかに周囲に報告して対象のブランチを`pull`しないよう呼びかけ、リポジトリの公開設定をprivateにした後、以下の手順を行うことになるでしょう。

### `git rebase`の手順

いきなり本番で`rebase`するのは怖いと思いますので、今回は練習用のリポジトリを作って試してみましょう。
私も知人にその形で教えてもらい、安心して実際の作業に取り組めました。

ではまず、練習用のディレクトリを作り、そこまで移動しましょう。

```bash
mkdir rebase-test
cd rebase-test
```

このディレクトリをgit管理できるようにしましょう。

```bash
git init
```

このディレクトリに、`test.md`というテスト用のファイルを作成します。

まずは`test.md`に、「1行書いてadd、commit」を3回繰り返して、コミット履歴を作りましょう。

```markdown:test.md
1 行目
```

```bash
git add -A
git commit -m "1行目のコミット"
```

```markdown:test.md
1 行目
25 行目 //この行を追加。あえて間違った数字を入れます
```

```bash
git add -A
git commit -m "25行目のコミット"  #ついでにコミットメッセージも間違えておきましょう。
```

```markdown:test.md

1 行目
25 行目
3 行目 //この行を追加
```

```bash
git add -A
git commit -m "3行目のコミット"
```

これらを、GitHubに`push`しましょう。

GitHubで新しいリポジトリを作り、`push an existing repository from the command line`にあるコードを貼り付けます。

```bash
git remote add origin https://github.com/GitHubアカウント名/rebase-test.git
git branch -M main
git push -u origin main
```

**ここまでで、 「不適切なコミット履歴をGitHubに`push`してしまった…」という私のやらかしを再現できました。**

では、 **作成したコミット履歴を`git log`で確認しましょう。**

```bash
git log
commit 60fac38abc402b3733aa5651513e3f25a7908257 (HEAD -> main)
Author: アカウント名 <メールアドレス>
Date:   Mon Jun 2 13:42:58 2025 +0900

3行目のコミット

commit 547093a7e9c21a3f19f458c0e5225c8f9d250267
Author: アカウント名 <メールアドレス>
Date:   Mon Jun 2 13:41:57 2025 +0900

25行目のコミット

commit 2334156677922d845e43766607b18f2d01f35b96
Author: アカウント名 <メールアドレス>
Date:   Mon Jun 2 13:41:22 2025 +0900

1行目のコミット
```

このように3件のコミットができています。

今回は、25行目と書いた部分は本来2行目ですので、この部分を`rebase`で編集してみましょう。

**編集したいコミットの一つ前のコミットの`id`をコピーします。**

今回は「25行目のコミット」を編集したいので、一つ前の、「1行目のコミット」の`id`をコピーします。`commit`という文字の横にあるハッシュ値です。

(コピーしたら、`q`で`git log`を抜けてください。)

**`git rebase -i`  の後ろに、コピーしたコミットidを貼り付けます。**

```bash
git rebase -i 2334156677922d845e43766607b18f2d01f35b96
```

こんな表示が出ます。

```bash
pick 547093a 25行目のコミット
pick 60fac38 3行目のコミット

# Rebase 2334156..60fac38 onto 2334156 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
```

Vim(シェル上で動くテキストエディタ)を操作して、コミット履歴を編集状態にします。

**`i`で編集モードに入ります。**

**編集したいコミット履歴の`pick`を`edit` に書き換えます。**

```bash
edit 547093a 25行目のコミット
pick 60fac38 3行目のコミット
```

**`Esc`で編集モードを抜けて、`:wq`で保存します。**

すると、ターミナルにはこう出ていると思います。

```bash
git rebase -i 2334156677922d845e43766607b18f2d01f35b96
Stopped at 547093a...  25行目のコミット
You can amend the commit now, with

  git commit --amend

Once you are satisfied with your changes, run

  git rebase --continue
```

この状態で、**`test.md`を修正します。**
テキストエディタに戻ると、このように「25行目のコミット」のところまで戻っており、3行目の記述がありません。

```markdown:test.md

1 行目
25 行目
```

では、25行目となっている部分を2行目に修正しましょう。

```markdown:test.md

1 行目
2 行目
```

`Ctrl`+ `s`などで変更を保存します。

終わったら、**修正をステージング、コミットします。**

```bash
git add -A
git commit --amend -m "2行目"
```

このとき、コミットメッセージを変えないこともできます。

```bash
# コミットメッセージを変えないでコミット
git commit --amend --no-edit
```

今回は変えましょう。

**`rebase`を終了します。**

```bash
git rebase --continue
```

すると、今変更した「2行目のコミット」を踏まえて、「3行目のコミット」が適用されます。

ここで、 **コンフリクト** が発生しました。

```bash
git rebase --continue
Auto-merging test.md
CONFLICT (content): Merge conflict in test.md
error: could not apply 60fac38... 3行目のコミット
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 60fac38... 3行目のコミット
```

今回は、2行目の部分を編集したため、その後の「3行目のコミット」内で、2行目の記述をどうするかでコンフリクトが起きています。

修正するためテキストエディタを開きましょう。

```markdown:test.md

1 行目
<<<<<<< HEAD (現在の変更)
2 行目
=======
25 行目
3 行目
>>>>>>> 60fac38 (3行目のコミット) (入力側の変更)

```

このように表示されているかと思います。

「`<<<<<<< HEAD` から `=======` までが現在のブランチ（HEAD）での変更内容、`=======` から `>>>>>>> 60fac38...` までが再適用しようとしているコミット（この場合は 「3行目のコミット」）での変更内容を示しています。
**これらのマーカーと不要なコードを削除し、正しいコードだけを残します。**

どちらかの変更を自動で適用するボタンもあるので、ふだんはそれを使っても大丈夫です。

今回は、25行目を消して2行目に変えて、その下に3行目ができてほしいので、変更を一気に取り込むことはせず、手動で以下のように編集しましょう。

```markdown:test.md

1 行目
2 行目
3 行目
```

コンフリクトを修正できたら、 **改めてステージングします。** `commit`はしません。

```bash
git add -A
```

**もう一度`rebase`モードを抜けます。**

```bash
git rebase --continue
```

環境によっては、以下のような表示になるかもしれません。

```bash
git commit --amend -m "2行目のコミット"
[detached HEAD 6734819] 2行目のコミット
 Date: Tue Jun 3 18:50:36 2025 +0900
 1 file changed, 1 insertion(+)
3行目のコミット

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto 5802abb
# Last commands done (2 commands done):
#    edit a8b2295 25行目のコミット
#    pick d0a6592 3行目のコミット
# No commands remaining.
# You are currently rebasing branch 'main' on '5802abb'.
#
"~/repos/rebase-test3/.git/COMMIT_EDITMSG" 15L, 466B
```

これはGitが「次のコミットのメッセージを編集しますか？」と聞いています。編集のためにVimが開いています。

今回はこのままでいいので、**`:wq`を押して保存し、Vimを抜けましょう。**

以下のような表示になっていれば、無事に`rebase`モードを抜けることができています。

```bash
Successfully rebased and updated refs/heads/main.
```

こうすることで、今回手動でコンフリクトを解決して`add`した内容が、「3行目のコミット」の内容として保存されることになります。

`rebase` はここまでです。
この時点で、ローカルリポジトリでは修正が完了しています。

最後に、**リモートリポジトリへ強制`push` します。**

```bash
git push --force
```

これで、晴れてコミット履歴を改変し、正しい状態のファイルのみをGitHubに上げ直すことができました。
GitHubにはもう「25行目」という誤った記述はありません。

お疲れ様でした。

# 最後に

私は初めからPrivateリポジトリにしていたこともあり、`rebase`するだけでなんとかことなきを得ました。
それでも、コミット履歴を改ざんしなくてはならないプレッシャー、使い慣れないVim操作、コンフリクトの解消…など、初心者には胃が痛い作業でした。

何が機密情報に当たるのか認識する必要性を痛感するとともに、「怪しければ入力しない」「安易に判断しない」という教訓にもなりました。

ただ、この`git rebase`、単純にコミットメッセージだけを修正したり、コミット履歴をきれいにしたりなど、ここまでのやらかしでないときにも十分使えます。
手数の一つとして持っておくに越したことはないでしょう。

# 参考サイト
## コミットの修正方法について
https://qiita.com/Lamaglama39/items/63d1914978e4e15536b5

こちらの記事では、コミットを修正する方法が複数紹介されています。何かあったときの対処を知るために、ご一読を推奨いたします。
`rebase`の手順を簡単に振り返りたいときにもおすすめです。

また、生成AIに聞くと`rebase` の代わりによく勧められる、**`git filter-repo`** についても書かれています。

今回用いた`rebase`との違いは、

- `rebase`: `直前のcommit`や`過去の単一のcommit`を修正したい場合
- `git filter-repo`: `過去の複数のcommit`、または`過去のすべてのcommit`を修正したい場合

と書かれています。

`git filter-repo`は公式推奨のライブラリのようです。気になる方はGitHubページもどうぞ。
https://github.com/newren/git-filter-repo

## 実務の場での対応について

https://qiita.com/ke-bo/items/433fe2a33a77ce007236

こちらの記事では、実務レベルでやってしまったときの対応について詳細に書かれています。
私の場合は、個人開発であり、かつ入力してしまった情報がMailtrapのみだったので、ここまではしませんでした。しかし、もしものときのために知っておくべき実践的な内容でした。
実際に実務の場でやってしまって困っている方、いざという時のために対応を知っておきたい方は、ぜひご一読ください。