
2026/01/08 4:03
**恐怖を抱くあなたへ贈る「Git Rebase」**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Summary
リベースはブランチの履歴を書き換えるため、個人用の機能ブランチでのみ使用し、作業を必ずバックアップしてください。
- まだ追加していない場合は upstream を追加:
。git remote add upstream https://github.com/OneBusAway/onebusaway-ios.git - upstream から最新の変更を取得:
。git fetch upstream - 安全のため現在の作業をフォークへプッシュ:
。git push origin <branch> - upstream/main に対してリベース:
。git rebase upstream/main - コンフリクトがあれば解消(コンフリクトマーカーを編集するか VS Code のマージ UI を使用)、各ファイルをステージ (
) し、git add …
で継続。git rebase --continue - 何か問題が起きたら
でリベース前の状態に戻す。git rebase --abort - リベース後は
でコミットを確認し、テスト/ビルドを実行。git log --oneline upstream/main..HEAD - 最後に 安全に強制プッシュ:
。共有ブランチ(例:git push --force-with-lease origin <branch>
)への強制プッシュは避けてください。main
これらの手順に従うことで、共有ブランチを安全に保ち、マージコンフリクトを減らし、個々の貢献者用機能ブランチをきれいに管理できます
本文
ハッカーニュースでの会話に参加しよう
複数の OneBusAway プロジェクトをメンテナンスしている立場から、私はよく貢献者にマージ前にブランチをリベースするよう依頼します。多くの場合、相手はためらいを示したり、恐怖心を露わにしたりします。そういう気持ちは分かります。リベースは作業を壊すという噂があり、オンライン上の警告もあまり役立ちません。
しかし実際に起こる最悪ケースは「ローカルクローンを削除してやり直す」だけです。それ以外は遠隔フォークとメインリポジトリは残っています。いつでも復旧できます。恐怖を払拭したら、ではリベースの手順を説明します。
なぜメンテナはリベースを求めるのか
main からブランチを作成して数日間作業すると、main は進化し続けます。別の PR がマージされ、あなたの PR の準備が整う頃には、ブランチの履歴は main から分岐しています。マージコミットで統合することもできますが、その結果としてインタリーブされたコミットが混在した不揃いな履歴になり、何が変わったかを把握しにくくなります。
リベースはあなたのコミットを現在の
main の上に再配置します。まるで今日ブランチを作成したように扱われます。その結果、クリーンで直線的な履歴が得られ、レビューやバグ追跡が格段に楽になります。
実際のコマンド
-
アップストリーム(元リポジトリ)がリモートとして設定されているか確認
フォークをクローンした場合は
が自分のフォーク指し示しているだけです。origingit remote -v -
メインリポジトリが表示されない場合は追加
git remote add upstream https://github.com/OneBusAway/onebusaway-ios.git -
アップストリームから最新の変更を取得
git fetch upstream -
自分の機能ブランチにいることを確認
git checkout your-branch-name -
リベース前に現在の作業をフォークへプッシュ
何か問題が起きたときに備えてバックアップです。git push origin your-branch-name -
アップストリームの
に対してリベースmaingit rebase upstream/mainコンフリクトが無ければ完了。コンフリクトがあれば Git が停止し、対象ファイルを教えてくれます。
コンフリクトマーカーの理解
競合したファイルを開くと次のような構造になります:
<<<<<<< HEAD const timeout = 5000; ======= const timeout = 10000; >>>>>>> upstream/main
と<<<<<<< HEAD
の間は、再配置されるコミット側(自分)のコードです。=======
と=======
の間は、>>>>>>> upstream/main
側で衝突したコードです。main
最終的に残すべきコードを決定し、マーカーを削除して残りのコードだけを残します。
VS Code では「Accept Current Change」「Accept Incoming Change」「Accept Both Changes」「Compare Changes」というボタンが表示されるため、手動でマーカーを探さなくても衝突を一つずつ解決できます。
コンフリクトが複雑な場合
- 単純ケース:同じ行を異なる内容に変更しただけ。どちらかを選ぶか合体させます。
- 難しいケース:複数コミットで同一ファイルが連続して衝突する場合、変更が互いに依存し、新しいベースに適用できないことがあります。
対処法:
- Squash からリベース
小さなコミットをまとめてロジカルなコミット数を減らします。 - Abort & 別アプローチ
で中止し、必要ならgit rebase --abort
から新しいブランチを作り手動で変更を適用します。main - rerere の活用
同じ衝突を何度も解決する場合は再利用設定を有効にします。
git config --global rerere.enabled true
衝突を解決したら:
git add path/to/resolved/file git rebase --continue
すべて完了するまで繰り返し、失敗した場合は
git rebase --abort で元に戻ります。
変更の検証
リベース後、次を確認します:
git log --oneline upstream/main..HEAD
これで
main より進んだ自分のコミットだけが表示されます。見た目が正しければビルドとテストを実行し、リベースにより潜在的な問題が生じていないか確認します。
強制プッシュ
リベース後はローカルブランチが遠隔ブランチから逸脱します。通常の
git push は失敗するので:
git push --force-with-lease origin your-branch-name
--force-with-lease は安全なオプションで、誰かが同時にプッシュしていれば失敗します。共有ブランチ(例:main)には絶対に強制プッシュしないでください。
それでもうまくいかなかったら
- 必要なら一時的なブランチへ作業をプッシュ
- ローカルクローンを削除
- フォークから再度クローン
- アップストリームリモートを追加
- リベースプロセスをやり直す
GitHub 上にコミットが残っている限り、いつでも復旧可能です。
もう一つの注意点
リベースはコミット履歴を書き換えます。これは自分だけが作業している機能ブランチなら問題ありません。しかし他人もそのブランチを基に作業している場合、リベースは避けるべきです。協力している場合は事前に連絡し、必要であればマージコミットを使う方が安全です。
以上です。リベースは「いつでも復旧できる」ことを理解すれば怖くありません。最悪ケースでは数分で再クローンするだけ。メリットはクリーンなプロジェクト履歴で、将来の保守やデバッグが楽になる点にあります。