症状
git push 実行時に以下のようなエラーが表示される。
! [rejected] main -> main (non-fast-forward)
error: failed to push some refs to 'origin'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart.
結論:まずこれを確認
- リモートに自分以外のコミットがないか
git fetch && git log origin/main..HEADで確認 - ある場合は
git pull --rebaseでリモートの変更を取り込む - ない場合は意図せず履歴が書き換わっていないか確認
操作フロー
flowchart TD
A[git push が rejected] --> B{git fetch して確認}
B --> C{リモートに新しいコミットあり?}
C -->|Yes| D[git pull --rebase を実行]
C -->|No| E{ローカルで履歴を書き換えた?}
D --> F[コンフリクトあり?]
F -->|Yes| G[コンフリクト解消]
F -->|No| H[git push を再実行]
G --> H
E -->|Yes| I[履歴の整合性を確認]
E -->|No| J[ブランチ名の確認]
I --> K[force push が必要か判断]
J --> L[正しいリモートか確認]
よくある原因
- リモートに他の人がpushした — チーム開発で最も多い原因
- 別端末で先にpushした — 同じ作業を複数環境で行っている場合
- git commit –amend を使った — 既にpush済みのコミットを修正した
- git rebase を使った — push済みのブランチをリベースした
- git reset を使った — push済みの履歴を巻き戻した
- ブランチ名が違う — ローカルとリモートで異なるブランチを指定している
- フォークしたリポジトリを操作している — upstreamとoriginを混同している
操作手順
ステップ1: 現在の状態を確認する
git status
git log --oneline -5
🔍 チェックポイント: 自分がどのブランチにいるか、最新のコミットが何かを確認
ステップ2: リモートの最新情報を取得する
git fetch origin
🔍 チェックポイント: エラーなく完了すること
ステップ3: ローカルとリモートの差分を確認する
# リモートにあってローカルにないコミット
git log HEAD..origin/main --oneline
# ローカルにあってリモートにないコミット
git log origin/main..HEAD --oneline
🔍 チェックポイント: 両方に差分がある場合は「分岐」している状態
ステップ4-A: リモートの変更を取り込む(通常のケース)
git pull --rebase origin main
🔍 チェックポイント: Successfully rebased and updated と表示されれば成功
コンフリクトが発生した場合:
# コンフリクトを解消してから
git add <ファイル名>
git rebase --continue
ステップ4-B: マージで取り込む場合
git pull origin main
🔍 チェックポイント: マージコミットが作成される。履歴を直線的に保ちたい場合は --rebase を使う
ステップ5: 再度pushする
git push origin main
🔍 チェックポイント: エラーなく完了し、リモートに反映されること
NG行動(やってはいけないこと)
- 安易に
git push --forceを使う — 他の人のコミットを消す可能性がある - 確認せずに
git pullする — 意図しないマージコミットが作られることがある - エラーを無視して再度pushを繰り返す — 状況は変わらない
git reset --hard origin/mainを安易に実行する — ローカルの作業が消える
⚠️ 警告: --force や --force-with-lease は、自分だけが使っているブランチ以外では使用を避ける。チームで共有しているブランチでは、他のメンバーの作業を破壊する可能性がある。
よくある質問(FAQ)
Q1: --force と --force-with-lease の違いは?
A: --force-with-lease は、自分が最後にfetchした時点からリモートが変わっていない場合のみ強制pushする。他の人のpushを上書きするリスクを軽減できる。ただし、完全な安全策ではない。
Q2: rebaseとmergeどちらを使うべき?
A: 履歴を直線的に保ちたい場合は rebase、マージした事実を残したい場合は merge。チームのルールに従う。迷う場合は merge が安全。
Q3: コンフリクトが複雑で解消できない場合は?
A: git rebase --abort でリベースを中止し、元の状態に戻せる。その後、git pull(マージ)を試すか、チームメンバーに相談する。
関連するトラブル
準備中
解決しない場合
- 公式ドキュメント: Git - git-push Documentation
- 確認すべきログ:
git reflogで過去の操作履歴を確認 - 次に調べるキーワード: 「git fetch vs pull」「git rebase conflict」「git force-with-lease」