git rebase に関するメモ

間が空きましたが、git の運用指針 - Life like a clown のフォロー記事、第 2 弾。

公開リポジトリに push した commit を rebase してはいけない

rebase に関しては、まだ使いどころが今一つ掴めないでいるのですが、明快な指針が一つ示されていました。

あぁ、このすばらしいリベース機能。しかし、残念ながら欠点もあります。その欠点はほんの一行でまとめることができます。

公開リポジトリにプッシュしたコミットをリベースしてはいけない

この指針に従っている限り、すべてはうまく進みます。もしこれを守らなければ、あなたは嫌われ者となり、友人や家族からも軽蔑されることになるでしょう。

Git - リベース

なぜ、公開リポジトリに push した commit に対して、後から rebase を行ってはいけないのかと言うと、「(rebase で作られた commit は元の commit と同内容でも別の commit となるため)rebase してしまうと push できなくなる」と言う理由のようです。何故、push できなくなってしまうのかについては こわくない Git と言うスライドで分かりやすく解説されていますので、このスライドの 104 〜 146 枚目を何度か追うと理解できると思います。

逆に、公開リポジトリに push する前であれば rebase を使って統合ブランチに追従するのは問題ないようです。入門 Git では、rebase 等を使用して自分の修正履歴を綺麗に整理して公開できる事も git のメリットの一つとして挙げられていました。

しかし、git では、個人の作業リポジトリがあるために、共用リポジトリに push して他のメンバーに結果を見せるまでは、今まで見てきたように rebase したり commit --amend したり reset --hard したり等の方法で歴史を訂正することができます。従来の集中型のシステムと異なり、間違いや失敗をおそれずに、自分の作業の都合だけで区切りの良い時点でコミットして行くことができ、また、自分の作ってきた歴史を綺麗に整理し直して見やすくしてから他人に自分の仕事の結果を見せることができるのが、大きな利点です。

※強調はブログ筆者によるもの

入門 Git - Chapter 6. グループで使う(p.93)

rebase の使いどころ

さて、rebase の使いどころに関してですが、rebaseはコミットグラフを綺麗にするためじゃなくてffマージをするためにあるのであった · GitHub と言う記事がありました。この記事自体は「FastForward マージの利点」に主眼が置かれて書かれているので直接的には関係ないのですが、そう言った FastForward マージの恩恵にあやかるために rebase が存在しているのかな、と言う気がします。また、Git - リベース での解説においても FastForward できるようにする事を念頭に rebase を実行している感が見て取れます。

一方で、git merge に関するメモ - Life like a clown でも書いたように、現在の git の運用においては「基本的に Non-FastForward でマージする」と言う方法が割とポピュラーになっているようなので、そう言った意味でも rebase を使うタイミングと言うのは、感覚的になかなか掴めないでいます。

入門 Git では、多人数で開発を行う場合の「トピックブランチからメインブランチへの統合作業」に際して、rebase に関する検討が記載されていました。

プロジェクトによっては、バージョン管理方針として、新しい変更が常に最新の状態から始まっていることを要求するものもあります(例えば X.org プロジェクトは最初に git を取り入れた頃からそのような方針を取っています)。

このような場合には、完成したブランチをまとめる前に、もう 1 ステップ、トピックブランチでした仕事の歴史のクリーンアップが必要になります。

…(中略)…

一般的に言って、プロジェクト全体で新しい変更が必ず最新状態の上にリベースされていることを要求するのはプロジェクトメンバーにとって不要な負担を強いることになり、また、トピックをリベースする時に競合解決を間違った場合に、どこにもそのトピックの正しく動くバージョンが残っていないという状況を引き起こすことになるので、メリットはあまりありません。

しかしながら、プロジェクト内でのメンバーの役割分担がきちんと行われていれば、完成したトピックが、そのトピックを開発中に共用リポジトリで並行して他のメンバーによって進められていた変更と意味的にもテキスト的にも重なることはほとんどないはずで、そうした場合には、後から完成したトピックを統合する前にリベースして最終的に記録される歴史を直線化することで、後から開発履歴を調べる際にスキップしないといけない不要なマージコミットを少なくすることができます。

プロジェクト全体の方針が新しい変更が必ず最新状態の上にリベースされていることを要求していなくても、トピックを新しく統合する前にリベースが容易に可能であればリベースするようにするのが、共同作業に参加するプロジェクトメンバーの良いしつけであると言えるでしょう。

入門 Git - Chapter 8. 分散環境とブランチの関連(p.118-120)

ちょっとまだ理解不足な部分も多いのですが、例えば、以下のような話でしょうか。



Non-FastForward によるマージを基本方針としている場合でも、容易に rebase 可能(≒コンフリクション無で rebase 可能?)な時は rebase してから merge すると、後から歴史を見た時や巻き戻す時に楽になると言う事が有り得るかもしれません。ただ、まだもやもやしてる部分もあるので、しばらくは「公開リポジトリにプッシュしたコミットをリベースしてはいけない」と言う指針のみ頭に入れて、試行錯誤して行こうかと思います。