git rebaseコマンドは、初心者が離れているべき魔法のGit voodooであると評判がありますが、注意して使用すると、開発チームの生活をはるかに容易にすることができます。 この記事では、git rebaseと関連するgit mergeコマンドを比較し、一般的なGitワークフローにリベースを組み込む可能性のあるすべての機,

概念の概要

git rebaseについて最初に理解すべきことは、git mergeと同じ問題を解決することです。 これらのコマンドはどちらも、あるブランチから別のブランチに変更を統合するように設計されています。

専用ブランチで新しい機能の作業を開始すると、別のチームメンバーがmasterブランチを新しいコミットで更新します。 これにより、gitをコラボレーションツールとして使用したことのある人には馴染み深い履歴が得られます。,

ここで、masterの新しいコミットは、作業している機能に関連しているとしましょう。 新しいコミットをfeatureブランチに組み込むには、マージまたはリベースの二つのオプションがあります。,

マージオプション

最も簡単なオプションは、masterブランチをフィーチャブランチにマージすることです。

git checkout feature git merge master

または、これをワンライナーに凝縮することができます。

 git merge feature master

これにより、新しい”マージコミット”が作成されます。feature両方のブランチの履歴を結びつけるブランチでは、次のような分岐構造が得られます。

マージは非破壊操作なので便利です。 既存のブランチは決して変更されません。, これにより、リベースの潜在的な落とし穴をすべて回避できます(以下で説明します)。

一方、これはまた、featureブランチは、上流の変更を組み込む必要があるたびに無関係なマージコミットを持つことを意味します。 masterが非常にアクティブな場合、これはあなたの機能ブランチの履歴をかなり汚染する可能性があります。 高度なgit logオプションでこの問題を軽減することは可能ですが、他の開発者がプロジェクトの履歴を理解するのが難しくなる可能性が,

Rebaseオプション

マージの代わりに、featureブランチをmasterブランチにリベースすることができます。

git checkout feature git rebase master

これにより、featureブランチ全体がザmasterブランチ、効果的にすべての新しいコミットを組み込みますmaster。 ものではなく統合を基準改定の再書き込みのプロジェクトの歴史創造によるブランドの新しいコミットコミット毎のです。,

リベースの主な利点は、よりクリーンなプロジェクト履歴を取得できることです。 まず、git merge必要な不要なマージコミットを排除します。 次に、上の図でわかるように、リベースは完全に線形のプロジェクト履歴をもたらします—featureのヒントに従って、フォークなしでプロジェクトの初めまで続くことができます。 これにより、git loggit bisectgitkのようなコマンドでプロジェクトを簡単にナビゲートできます。,

しかし、この自然のままのコミット履歴には、安全性とトレーサビリティの二つのトレードオフがあります。 リベースの黄金律に従わないと、プロジェクト履歴を書き直すことは、コラボレーションワークフローにとって壊滅的な可能性があります。 そして、それほど重要ではありませんが、リベーシングはマージコミットによって提供されるコンテキストを失います。

Interactive Rebasing

Interactive rebasingを使用すると、コミットが新しいブランチに移動されるときにコミットを変更することができます。, これは、ブランチのコミット履歴を完全に制御できるため、自動化されたリベースよりもさらに強力です。 通常、これはフィーチャブランチをmasterにマージする前に、乱雑な履歴をクリーンアップするために使用されます。,

インタラクティブなリベースセッションを開始するには、iオプションをgit rebaseコマンドに渡します。

git checkout feature git rebase -i master

これにより、移動しようとしているすべてのコミットをリストするテキストエディタが開きます。

pick 33d5b7a Message for commit #1 pick 9480b3d Message for commit #2 pick 5c67e61 Message for commit #3

このリストは、rebaseの実行後にブランチがどのように見えるかを正確に定義しています。 pickコマンドを変更したり、エントリを並べ替えたりすることで、ブランチの履歴を好きなように見せることができます。, たとえば、2番目のコミットで1番目のコミットで小さな問題が修正された場合、fixupコマンドでそれらを単一のコミットに凝縮することができます。

pick 33d5b7a Message for commit #1 fixup 9480b3d Message for commit #2 pick 5c67e61 Message for commit #3

ファイルを保存して閉じると、Gitは指示に従ってリベースを実行し、次のようなプロジェクト履歴が生成されます。

このような重要でないコミットは、機能の履歴を理解しやすくします。 これは、git mergeではできないことです。,

リベーシングの黄金律

リベーシングが何であるかを理解したら、学ぶべき最も重要なことは、それをしないときです。 git rebaseの黄金ルールは、パブリックブランチでは決して使用しないことです。

たとえば、masterfeatureブランチにリベースした場合にどうなるかを考えてください。

リベースにより、master内のすべてのコミットがfeature。 問題は、これがリポジトリでのみ起こったことです。, 他のすべての開発者はまだ元のmasterで作業しています。 リベースすると新しいコミットが発生するため、Gitはあなたのmasterブランチの履歴が他のすべてのブランチから分岐したと考えます。

二つのmasterブランチを同期させる唯一の方法は、それらをマージし直すことです。その結果、余分なマージコミットと同じ変更を含む二つのコミットセット(元のもの、およびリベースされたブランチからのもの)が追加されます。 言うまでもなく、これは非常に混乱する状況です。,だから、あなたが実行する前にgit rebase、常に自分自身に尋ねる、”他の誰かがこのブランチを見ていますか?”答えが”はい”の場合は、キーボードから手を離して、変更を加える非破壊的な方法について考え始めます(例:git revertコマンド)。 それ以外の場合は、好きなだけ履歴を書き直しても安全です。

強制プッシュ

リベースされたmasterブランチをリモートリポジトリにプッシュしようとすると、Gitはリモートmasterブランチと競合するため、, しかし、次のように--forceフラグを渡すことで、プッシュを強制することができます。

# Be very careful with this command! git push --force

これにより、リモートのmasterブランチがリポジトリからリベースされたものと一致するように上書きされ、残りのチームにとって非常に混乱させます。 いうよう十分注意してくださいこのコマンドを使用する場合にのみがどうなのかを知りだしています。

強制プッシュする必要があるのは、プライベート機能ブランチをリモートリポジトリにプッシュした後にローカルクリーンアップを実行したときだけです(バックアップのためなど)。, これは、”おっと、私は本当に機能ブランチの元のバージョンをプッシュしたくありませんでした。 代わりに現在のものを取る。”繰り返しになりますが、featureブランチの元のバージョンからのコミットを誰も作業していないことが重要です。

ワークフローチュートリアル

リベースは、チームが慣れ親しんでいる限り、既存のGitワークフローに組み込むことができます。 このセクションでは、機能の開発のさまざまな段階でリベーシングが提供できる利点について見ていきます。,

git rebaseを活用するワークフローの最初のステップは、各機能の専用ブランチを作成することです。 これにより、リベースを安全に利用するために必要なブランチ構造が得られます。

ローカルクリーンアップ

ワークフローにリベースを組み込む最も良い方法の一つは、ローカルの進行中の機能をクリーンアップすることです。 定期的に対話型リベースを実行することにより、機能内の各コミットに焦点が当てられ、意味があることを確認できます。, これにより、分離されたコミットに分割することを心配することなくコードを記述できます—事実の後に修正することができます。

呼び出すときgit rebase、あなたは新しいベースのための二つのオプションがあります:機能の親ブランチ(例えば、master)、またはあなたの インタラクティブリベースセクションの最初のオプションの例を見ました。 後者のオプションは、最後のいくつかのコミットを修正するだけでよい場合に便利です。 たとえば、次のコマンドは、最後の3つのコミットのみの対話型リベースを開始します。,

git checkout feature git rebase -i HEAD~3

指定することにより、HEAD~3新しいベースとして、あなたは実際にブランチを移動していない—あなたはちょうど対話的にそれに続く3つのコミットを書き直しています。 これは上流の変更をfeatureブランチに組み込まないことに注意してください。

このメソッドを使用してフィーチャ全体を書き直したい場合は、git merge-baseコマンドは、featureブランチの元のベースを見つけるのに役立ちます。, 次に、元のベースのコミットIDを返します。git rebaseに渡すことができます。

git merge-base feature master

この対話型リベーシングの使用は、git rebaseをワークフローに導入するのに最適な方法です。 他の開発者が表示される唯一のものは、きれいで簡単にフォローできる機能のブランチ履歴でなければならない完成品です。

しかし、これはプライベート機能ブランチでのみ機能します。, 同じ機能ブランチを介して他の開発者とコラボレーションしている場合、そのブランチは公開されており、その履歴を書き直すことはできません。

対話型リベースでローカルコミットをクリーンアップするためのgit merge代替はありません。

アップストリームの変更をフィーチャに組み込む

概念の概要セクションでは、masterからのアップストリームの変更をgit mergeまたはgit rebaseのいずれかを使用してフィーチャブランチがどのように組み込むことができるかを説明しました。, マージは、リポジトリの履歴全体を保持する安全なオプションですが、リベースは、フィーチャブランチをmasterの先端に移動することによ

このgit rebaseの使用は、ローカルクリーンアップに似ています(同時に実行できます)が、プロセスでは、masterからのアップストリームコミットが組み込まれています。masterの代わりにリモートブランチにリベースすることは完全に合法であることに注意してください。, これは、同じ機能を別の開発者とコラボレーションし、変更をリポジトリに組み込む必要がある場合に発生する可能性があります。,

たとえば、あなたとJohnという別の開発者がfeatureブランチにコミットを追加した場合、Johnのリポジトリからリモートfeatureブランチをフェッチした後、リポジトリは次のようになります。

このフォークを解決するには、:ローカルのfeaturejohn/featureとマージするか、ローカルのfeaturejohn/featureの先端にリベースします。,

このリベースは、ローカルのfeatureコミットのみが移動されるため、リベースの黄金ルールに違反しないことに注意してください。 これは言うことのよう、”ジョンが既にしたものに私の変更を加えなさい。”ほとんどの状況では、これはマージコミットを介してリモートブランチと同期するよりも直感的です。

デフォルトでは、git pullコマンドはマージを実行しますが、--rebaseオプションを渡すことによって、リモートブランチをリベースと統合するように強制することができます。,

プルリクエストを使用した機能のレビュー

コードレビュープロセスの一部としてプルリクエストを使用する場合は、プルリクエストを作成した後にgit rebaseを使用しないようにする必要があります。 プルリクエストを行うとすぐに、他の開発者はあなたのコミットを見ています。 その履歴を書き直すと、Gitとあなたのチームメイトが機能に追加されたフォローアップコミットを追跡することができなくなります。

他の開発者からの変更は、git mergeの代わりにgit rebase組み込む必要があります。,

このため、通常、プルリクエストを送信する前に、対話型のリベースでコードをクリーンアップすることをお勧めします。

承認された機能の統合

機能がチームによって承認された後、masterブランチの先端に機能を再ベース化することができます。git mergeを使用して機能をメインコードベースに統合します。,

これは、上流の変更をfeatureブランチに組み込むのと同様の状況ですが、masterブランチでコミットを書き直すことはできないため、最終的にgit mergeを使用して機能を統合する必要があります。 ただし、マージの前にリベースを実行することにより、マージが早送りされ、完全に線形の履歴が得られることが保証されます。 これにより、プル要求中に追加されたフォローアップコミットをスカッシュすることもできます。,

git rebaseに完全に慣れていない場合は、いつでも一時的なブランチでリベースを実行できます。 そうすれば、誤って機能の履歴を台無しにした場合は、元のブランチをチェックアウトして再試行することができます。 たとえば、

git checkout feature git checkout -b temporary-branch git rebase -i master # git checkout master git merge temporary-branch

Summary

ブランチのリベースを開始するために本当に知っておく必要があるのはそれだけです。, 不要なマージコミットのないクリーンで線形な履歴を希望する場合は、git rebase代わりにgit merge別のブランチからの変更を統合

一方、プロジェクトの完全な履歴を保持し、パブリックコミットを書き直すリスクを避けたい場合は、git merge固執することができます。 どちらのオプションも完全に有効ですが、少なくとも今はgit rebaseの利点を活用するオプションがあります。