プログラミング
Git rebase -I はそれほど怖くない
Git rebase -I is not that scary (cachebag.sh)
要約
Junior devが恐れがちな`git rebase -i`コマンドについて、その仕組みと安全性を解説する記事です。テキストエディタでコミットの並べ替えや編集、削除を行うインタラクティブな操作であり、`git rebase --abort`や`git reflog`、ブランチのバックアップといった安全策があるため、恐れる必要はないと述べています。
全文翻訳
ジュニア開発者としての私のキャリア初期に遭遇した最も衝撃的なことの1つは、git rebase -iを取り巻く恐怖です。多くの点で私よりもはるかに賢い同僚の間でさえ、多くの開発者がこのコマンドを恐れる傾向があるようです。
実際、あなたが実行したときに何が起こるか:
git rebase -i HEAD~4
Gitは、実に平凡なことを行います。テキストファイルを開きます。ターミナルから作業していて、Gitの設定をいじっていない場合、git config --global core.editor "_YOUR-EDITOR_" は、Vimを使いこなすことへの恐怖を和らげるのに役立ちます。
pick a1b2c3d Add user model
pick e4f5g6h Fix typo in user model
pick i7j8k9l Add login endpoint
pick m0n1o2p WIP debugging login
# コマンド:
# p, pick = コミットを使用する
# r, reword = コミットを使用するが、コミットメッセージを編集する
# s, squash = コミットを使用するが、前のコミットにマージする
# f, fixup = "squash"と同様だが、このコミットのメッセージは破棄する
# d, drop = コミットを削除する
新しいリベーサーがここで注意すべき価値のある点は、これが計画であり、アクションではないということです。リベースが開始されたという事実を除けば、技術的には何も起こっていません。気が変わった場合は、git rebase --abortを実行して、再開するか、諦める(理想的には前者)ことができます。
各行は命令であり、ターゲットにしたコミットの再生が開始されます。これらの命令を好きなように組み合わせることができます。
r a1b2c3d Add user model
pick e4f5g6h Fix typo in user model
pick i7j8k9l Add login endpoint
d m0n1o2p WIP debugging login
# コマンド:
# p, pick = コミットを使用する
# r, reword = コミットを使用するが、コミットメッセージを編集する
# s, squash = コミットを使用するが、前のコミットにマージする
# f, fixup = "squash"と同様だが、このコミットのメッセージは破棄する
# d, drop = コミットを削除する
ここで何が起こったか:
1. この例では、Gitは最初のコミットで一時停止し、メッセージをリワードできるようにします。
2. dまたはdropは、WIPデバッグコミットを完全に削除します。この同じ結果は、行を完全に削除することでも達成できます。
中間の2つのコミットは、周囲のコミットを変更したにもかかわらず、変更されませんでした。最終結果は4つではなく、合計3つのコミットになります。
率直に言って、それだけです。大したことではありません。その例が何をするかを理解できれば、インタラクティブなリベースは、あなたの人生をより困難にするのではなく、より容易にするツールになります。
インタラクティブなリベースの目的を軽視する人々にもよくあることがあります。それらの議論に深入りせずに、私は率直に言いたいと思います。私の意見では、クリーンなブランチ履歴を気にしないのであれば(リベースが提供する改善のごく一部)、ソフトウェアに対してどれほど真剣であるかについては、より懐疑的になります。
「でも、もし私がそれを台無しにしたらどうなるの?」
実際には、3つの理由で作業を失うことは非常に困難です。
いつでも中止できます。前述のように、git rebase --abortを使用すると、ブランチは開始前の状態に正確に戻ります。
リベースはコミットを破壊しません—新しいコミットを作成します。これが重要なメンタルモデルです。リベースは古いコミットを編集しません。新しいコミットを作成し、ブランチポインタをそれらに移動させるだけです。古いコミットは、ガベージコレクションが介入するまでの間、参照されずにGitのオブジェクトデータベースにそのまま残ります。
reflogはすべてを記憶しています。これは、私が最初のインターンシップで、同僚が以前に行ったコミットを削除したいと思っていたと勘違いして、彼のブランチの履歴を消去したときに、特に理解することが重要でした。
Gitは、ブランチがどこを指していたかのジャーナルを保持しています:
git reflog
リベース前のエントリを見つけて復元します:
git reset --hard HEAD@{4}
リベース全体が元に戻されます。
このセーフティネットは常に存在するため、失敗したリベースの最悪の現実的な結果は、reflogを数分間調べることになります。そして、reflogでさえ daunting に感じる場合(ただし、私の投稿のここまで来たのであれば、それを処理するのに十分な能力があるはずですが)、もちろん、低レベルの保険ポリシーがあります。
git branch backup-before-rebase
これで、リベース前の状態に名前が付きました。何か問題が発生した場合は、git reset --hard backup-before-rebase を実行すれば安全に戻れます。
競合
再生中のコミットが、以前の変更(通常は並べ替え時、または更新されたメインにリベースする場合)と競合することがあります。Gitは停止し、文字通り指示を表示します。
マージ競合を解決するのと同じように競合を解決し、git add ファイルを実行してから git rebase --continue を実行します。
これはおそらく人々を最も悩ませることだと思います。しかし、競合はGitの新しい概念ではありません。実際、インタラクティブなリベースの文脈では、競合はマージよりも解決しやすいと主張します。なぜなら、一度に1つのコミットのみを扱い、ブランチ全体ではないからです。
義務的な警告
ソフトウェアのあらゆるものと同様に、特にリベースのような破壊的なものについては、何をしているのかを理解するために多大な注意と努力を払うべきです。はい、作業は回復できますが、それは怠惰であることの言い訳にはなりません。
私が従う良い一般的な経験則は、レビューの前または最中に、自分のフィーチャーブランチを自由にリベースできるようにすることです。git push --force-with-lease を使用して結果を自分のリモートブランチにプッシュすることは正常であり、問題ありません(--force-with-lease は、誰かが途中でプッシュした場合にプッシュを拒否します。常にプレーンな --force よりも優先してください)。
結論
私は、自分の価値を理解している開発者であれば、少なくとも非常に単純なインタラクティブなリベースを歩むことができるべきだと個人的に考えています。この投稿は、いつ、なぜそれを使用すべきか(ただし、私はそれを惜しみなく使用すべきだと信じていますが)についてはあまり触れていません。主にプロセスをわかりやすくし、試してみることを奨励するためです。特にジュニア/初心者開発者であれば。