はじめに

「コミットを間違ったブランチにしてしまった」「コミットメッセージを修正したい」「pushした内容を取り消したい」「突然detached HEAD状態になった」「大きなファイルを誤ってコミットしてしまった」。Gitを使った開発では、これらのトラブルに遭遇することは珍しくありません。

本記事では、日常的に発生しやすいGitトラブルの原因と解決方法を体系的に解説します。この記事を読み終えると、以下のことができるようになります。

  • 間違ったブランチへのコミットを正しいブランチに移動できる
  • git commit --amendでコミットメッセージや内容を修正できる
  • git push --force-with-leaseでpush済みコミットを安全に取り消せる
  • detached HEAD状態を理解し、適切に復帰できる
  • 大きなファイルを誤ってコミットした場合に履歴から削除できる

実行環境と前提条件

本記事の内容は、以下の環境で動作確認を行っています。

項目 要件
Git 2.40以上
OS Windows 10/11、macOS 12以上、Ubuntu 22.04以上
ターミナル コマンドプロンプト、PowerShell、Terminal.app、bash等
エディタ VS Code推奨

前提条件として、以下の知識があることを想定しています。

  • コマンドライン操作の基礎知識(cdls/dirmkdir等)
  • テキストエディタの基本操作
  • Gitの基本コマンド(git addgit commitgit pushgit branch)の理解

Gitトラブル対処の基本方針

Gitトラブルに遭遇した際は、以下の基本方針で対処することをおすすめします。

状況 対処方針
ローカルのみの変更(未push) 履歴の書き換えが可能(reset、amend等)
リモートにpush済み 履歴の書き換えは慎重に(revert推奨、またはforce-with-lease)
チームで共有済み revertで打ち消しコミットを作成(履歴は書き換えない)

まず現在の状態を確認することが重要です。

1
2
3
4
5
6
7
8
# 現在のブランチと状態を確認
git status

# コミット履歴を確認
git log --oneline -5

# リモートとの差分を確認
git log origin/main..HEAD --oneline

間違ったブランチへのコミットを修正する

開発中にmainブランチで作業してしまい、本来featureブランチにコミットすべき変更をmainにコミットしてしまうケースは頻繁に発生します。

状況の確認

まず、誤ってコミットした状況を確認しましょう。

1
2
3
4
5
6
7
8
$ git branch
* main
  feature/new-function

$ git log --oneline -3
a1b2c3d (HEAD -> main) 誤ってmainにコミットした変更
e4f5g6h 前回の正しいコミット
i7j8k9l さらに前のコミット

未pushの場合:コミットを別ブランチに移動する

リモートにpushしていない場合は、以下の手順で安全にコミットを移動できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 1. 移動先のブランチに切り替え
git switch feature/new-function

# 2. mainブランチの最新コミットを取り込む(cherry-pick)
git cherry-pick main

# 3. mainブランチに戻る
git switch main

# 4. mainブランチのコミットを取り消す(直前の1コミット)
git reset --hard HEAD~1

実行結果の確認を行います。

1
2
3
4
5
6
7
$ git log --oneline -3 feature/new-function
b2c3d4e (HEAD -> feature/new-function) 誤ってmainにコミットした変更
...

$ git log --oneline -3 main
e4f5g6h (HEAD -> main) 前回の正しいコミット
i7j8k9l さらに前のコミット

複数コミットを移動する場合

複数のコミットを移動する必要がある場合は、範囲指定でcherry-pickを実行します。

1
2
3
4
5
6
7
8
9
# 移動先ブランチに切り替え
git switch feature/new-function

# 複数コミットをcherry-pick(古い順に適用)
git cherry-pick e4f5g6h..a1b2c3d

# mainブランチに戻ってリセット
git switch main
git reset --hard HEAD~3  # 移動したコミット数分だけ戻す

push済みの場合の対処

既にリモートにpush済みの場合、履歴の書き換えには注意が必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 移動先ブランチでcherry-pick
git switch feature/new-function
git cherry-pick main
git push origin feature/new-function

# mainブランチをリセット
git switch main
git reset --hard HEAD~1

# 強制プッシュ(--force-with-leaseを使用)
git push --force-with-lease origin main

--force-with-leaseオプションは、他の人がリモートブランチを更新していないことを確認してからプッシュするため、--forceより安全です。

コミットメッセージの修正(amend)

コミットメッセージのタイポや内容の不備を修正したい場合、git commit --amendを使用します。

直前のコミットメッセージを修正する

1
2
3
4
5
# エディタが開き、コミットメッセージを編集できる
git commit --amend

# または、コマンドラインで直接メッセージを指定
git commit --amend -m "修正後のコミットメッセージ"

実行例を見てみましょう。

1
2
3
4
5
6
7
$ git log --oneline -1
a1b2c3d feat: ユーザー認証機能を実装(タイポあり)

$ git commit --amend -m "feat: ユーザー認証機能を実装"

$ git log --oneline -1
d4e5f6g feat: ユーザー認証機能を実装

コミットハッシュが変わっていることに注目してください。amendは新しいコミットを作成するため、ハッシュ値が変更されます。

直前のコミットにファイルを追加する

コミット漏れのファイルがある場合も、amendで対処できます。

1
2
3
4
5
# 追加したいファイルをステージング
git add forgotten-file.js

# --no-editオプションでメッセージを変更せずにコミットに追加
git commit --amend --no-edit

直前のコミットからファイルを除外する

逆に、コミットに含めるべきでないファイルを除外したい場合は以下のようにします。

1
2
3
4
5
6
7
8
# コミットをソフトリセット(変更は保持)
git reset --soft HEAD~1

# 除外したいファイルをアンステージ
git restore --staged unwanted-file.js

# 再度コミット
git commit -c ORIG_HEAD

push済みコミットのamend

リモートにpush済みのコミットをamendした場合、強制プッシュが必要になります。

1
2
3
4
5
# コミットメッセージを修正
git commit --amend -m "修正後のメッセージ"

# 安全な強制プッシュ
git push --force-with-lease origin feature/my-branch

注意点: チームで共有しているブランチ(main、develop等)では、push済みコミットのamendは避けてください。他のメンバーの作業に影響を与える可能性があります。

pushした内容の取り消し

リモートにpushした内容を取り消す方法は、状況によって異なります。

方法1:revertで打ち消しコミットを作成する(推奨)

チームで共有しているブランチでは、履歴を書き換えずにrevertで打ち消しコミットを作成することを推奨します。

1
2
3
4
5
6
7
8
# 直前のコミットを打ち消す
git revert HEAD

# 特定のコミットを打ち消す
git revert a1b2c3d

# 複数コミットを打ち消す(個別にrevertコミットが作成される)
git revert HEAD~3..HEAD

revertの実行例を確認しましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ git log --oneline -3
a1b2c3d (HEAD -> main) 問題のあるコミット
e4f5g6h 前回のコミット
i7j8k9l さらに前のコミット

$ git revert HEAD
[main b2c3d4e] Revert "問題のあるコミット"
 1 file changed, 1 deletion(-)

$ git log --oneline -4
b2c3d4e (HEAD -> main) Revert "問題のあるコミット"
a1b2c3d 問題のあるコミット
e4f5g6h 前回のコミット
i7j8k9l さらに前のコミット

revertは新しいコミットを作成するため、履歴が保持され安全です。

方法2:resetと強制プッシュで履歴を書き換える

個人ブランチで履歴を完全に消したい場合は、resetと強制プッシュを使用します。

1
2
3
4
5
# ローカルで履歴を書き換え
git reset --hard HEAD~1

# 強制プッシュ(安全版)
git push --force-with-lease origin feature/my-branch

–forceと–force-with-leaseの違い

オプション 動作 安全性
--force 無条件でリモートを上書き 低い(他者の変更を消す可能性)
--force-with-lease リモートが予期した状態の場合のみ上書き 高い(他者の変更があれば失敗)

--force-with-leaseは、最後にfetchした時点のリモートの状態と現在のリモートの状態を比較し、変更がなければプッシュを許可します。これにより、他のメンバーがプッシュした変更を誤って上書きすることを防げます。

1
2
3
4
5
# 他の人がプッシュしていた場合、force-with-leaseは失敗する
$ git push --force-with-lease origin main
To github.com:user/repo.git
 ! [rejected]        main -> main (stale info)
error: failed to push some refs to 'github.com:user/repo.git'

この場合は、まずfetchして差分を確認してから対処を検討します。

1
2
3
git fetch origin
git log origin/main..HEAD --oneline
git log HEAD..origin/main --oneline

detached HEAD状態からの復帰

detached HEAD状態は、特定のコミットを直接チェックアウトした際などに発生します。この状態では、新しいコミットがどのブランチにも属さなくなる可能性があります。

detached HEADとは何か

通常、HEADはブランチを指し、ブランチがコミットを指します。

通常の状態:
HEAD -> main -> commit A

detached HEAD状態:
HEAD -> commit A(ブランチを経由していない)

detached HEADになる原因

主な原因は以下の通りです。

1
2
3
4
5
6
7
8
# 特定のコミットを直接チェックアウト
git checkout a1b2c3d

# タグをチェックアウト
git checkout v1.0.0

# リモートブランチを直接チェックアウト
git checkout origin/main

実行時には警告メッセージが表示されます。

1
2
3
4
5
6
7
$ git checkout a1b2c3d
Note: switching to 'a1b2c3d'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
...

状態の確認方法

1
2
3
4
5
6
7
$ git status
HEAD detached at a1b2c3d

$ git branch
* (HEAD detached at a1b2c3d)
  main
  feature/new-function

復帰方法1:既存のブランチに戻る

単純にブランチに戻りたい場合は、switchまたはcheckoutを使用します。

1
2
3
4
# ブランチに切り替え
git switch main
# または
git checkout main

復帰方法2:detached HEAD状態でのコミットを保存する

detached HEAD状態で作業してコミットを作成した場合、その作業を保存するにはブランチを作成します。

1
2
3
4
# 現在の状態から新しいブランチを作成
git switch -c save-my-work
# または
git checkout -b save-my-work

実行例を確認しましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ git status
HEAD detached at b2c3d4e

$ git log --oneline -3
b2c3d4e (HEAD) detached状態での作業コミット
a1b2c3d 元のコミット
e4f5g6h さらに前のコミット

$ git switch -c save-my-work
Switched to a new branch 'save-my-work'

$ git status
On branch save-my-work

復帰方法3:迷子になったコミットを救出する

detached HEAD状態で作業後、ブランチを作成せずに別のブランチに切り替えてしまった場合、コミットが迷子になります。この場合はgit reflogで救出できます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# reflogでHEADの移動履歴を確認
$ git reflog
c3d4e5f (HEAD -> main) HEAD@{0}: checkout: moving from b2c3d4e to main
b2c3d4e HEAD@{1}: commit: detached状態での作業コミット
a1b2c3d HEAD@{2}: checkout: moving from main to a1b2c3d

# 迷子のコミットからブランチを作成
$ git branch recovered-work b2c3d4e

# または直接cherry-pick
$ git cherry-pick b2c3d4e

reflogはGitの操作履歴を記録しており、デフォルトで90日間保持されます。迷子になったコミットを見つける際の強力なツールです。

大きなファイルを誤ってコミットした場合の対処

動画ファイル、データベースダンプ、依存パッケージなど、大きなファイルを誤ってコミットしてしまうと、リポジトリが肥大化し、クローンやプッシュに時間がかかるようになります。

問題の発見

リポジトリのサイズが大きくなっていることに気づく典型的なケースです。

1
2
3
4
5
6
# リポジトリのサイズを確認
$ du -sh .git
500M    .git

# 大きなファイルを特定(Git 2.18以降)
$ git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort -rnk2 | head -10

未pushの場合:直前のコミットから除外する

まだpushしていない場合は、比較的簡単に対処できます。

1
2
3
4
5
6
# 直前のコミットの場合
git reset --soft HEAD~1
git restore --staged large-file.zip
echo "large-file.zip" >> .gitignore
git add .gitignore
git commit -m "feat: 機能実装(大きなファイルを除外)"

push済みの場合:git filter-branchで履歴から削除する

Git公式のfilter-branchを使用して履歴からファイルを削除できますが、非推奨になりつつあります。

1
2
3
4
5
6
7
8
# filter-branchで履歴から削除(非推奨だが動作する)
git filter-branch --force --index-filter \
  'git rm --cached --ignore-unmatch large-file.zip' \
  --prune-empty --tag-name-filter cat -- --all

# ガベージコレクションでサイズを削減
git reflog expire --expire=now --all
git gc --prune=now --aggressive

push済みの場合:git filter-repo(推奨)

git filter-repoはGit公式が推奨する高速なツールです。別途インストールが必要です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# インストール(pip経由)
pip install git-filter-repo

# 大きなファイルを履歴から削除
git filter-repo --path large-file.zip --invert-paths

# 複数ファイルを削除
git filter-repo --path file1.zip --path file2.mp4 --invert-paths

# パターンで削除
git filter-repo --path-glob '*.zip' --invert-paths

push済みの場合:BFG Repo-Cleaner(高速)

BFG Repo-Cleanerは大きなファイルの削除に特化した高速ツールです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# BFGをダウンロードして実行
# https://rtyley.github.io/bfg-repo-cleaner/

# 100MB以上のファイルを削除
java -jar bfg.jar --strip-blobs-bigger-than 100M

# 特定のファイルを削除
java -jar bfg.jar --delete-files large-file.zip

# クリーンアップ
git reflog expire --expire=now --all
git gc --prune=now --aggressive

履歴書き換え後のリモート更新

履歴を書き換えた後は、リモートへの強制プッシュが必要です。

1
2
3
4
5
# すべてのブランチを強制プッシュ
git push --force-with-lease --all origin

# タグも更新
git push --force-with-lease --tags origin

重要な注意点:

  • チームで共有しているリポジトリで履歴を書き換える場合は、事前に全員に通知してください
  • 他のメンバーはgit fetch --allの後にgit reset --hard origin/ブランチ名が必要になります
  • 履歴の書き換えは最後の手段として、可能な限り避けてください

予防策:.gitignoreとpre-commitフック

大きなファイルのコミットを防ぐための予防策を設定しましょう。

1
2
3
4
5
6
7
# .gitignoreに追加
*.zip
*.tar.gz
*.mp4
*.mov
node_modules/
vendor/

pre-commitフックで大きなファイルのコミットを防ぐこともできます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# .git/hooks/pre-commit
#!/bin/bash

# 10MB以上のファイルをブロック
max_size=10485760

for file in $(git diff --cached --name-only); do
  if [ -f "$file" ]; then
    size=$(wc -c < "$file")
    if [ "$size" -gt "$max_size" ]; then
      echo "Error: $file is larger than 10MB"
      exit 1
    fi
  fi
done

トラブル発生時の緊急対応チェックリスト

Gitトラブルが発生した際は、以下のチェックリストに従って対応してください。

1. 現状の確認

1
2
3
4
# 現在の状態を確認
git status
git branch -v
git log --oneline -5

2. リモートとの差分確認

1
2
3
4
5
6
# リモートの最新情報を取得
git fetch origin

# ローカルとリモートの差分を確認
git log origin/main..HEAD --oneline  # ローカルにあってリモートにない
git log HEAD..origin/main --oneline  # リモートにあってローカルにない

3. 安全な復旧ポイントの確保

1
2
3
4
5
# 現在の状態でバックアップブランチを作成
git branch backup-$(date +%Y%m%d-%H%M%S)

# reflogで操作履歴を確認
git reflog

4. 対処の実行

本記事で解説した各トラブルに対応した手順を実行します。

5. 結果の確認

1
2
3
4
5
6
# 状態を確認
git status
git log --oneline -5

# 問題が解決したらバックアップブランチを削除
git branch -d backup-20260102-120000

まとめ

本記事では、日常的に発生しやすいGitトラブルとその解決方法を解説しました。

トラブル 主な解決方法
間違ったブランチへのコミット cherry-pick + reset
コミットメッセージの修正 git commit –amend
push済み内容の取り消し git revert(推奨)または force-with-lease
detached HEAD状態 ブランチ作成またはreflogで救出
大きなファイルの誤コミット filter-repo、BFG、または filter-branch

Gitトラブルに遭遇した際は、まず冷静に現状を確認し、バックアップブランチを作成してから対処することをおすすめします。また、git reflogは多くのトラブルから救出できる強力なツールなので、覚えておくと安心です。

参考リンク