初心者のためのインタラクティブリベース入門

原著作:ストライド 2018年1月16日 52,731 reads

ストライドハッカーノーンのプロフィール画像

について

@StrideStride

情報技術・サービス

facebook social iconTwitter social icon

今年の初めに初めてインタラクティブリベースをして、それで何ができるかと感心しました。 また、最初は少し複雑であることもわかりました。

また、これは非常に強力で、基本的に歴史を書き換えることができるため、始める前に小さな警告をします。 Git とリベースが良いアイデアかどうかについては、多くの考え方があります。 この記事ではそのような議論には踏み込まず、純粋に対話型リベースの基本的な使い方を説明します。

TL;DR

  • 対話型リベースは、編集、削除、破棄など多くの方法でコミットを変更するのに使うことができます。
  • 対話的リベースをどこで開始するかを Git に伝えるには、変更したいコミットの直前にあるコミットの SHA-1 またはインデックスを使います。
  • 対話的リベース中、編集するタグを付けたコミットで Git が一時停止した場合、ワークフローは通常のコミット処理と変わりません – ファイルのステージとそのコミットを行うのです。
  • 対話的リベースは新しい SHA-1 を作成するので、リモートブランチにプッシュしていないコミットに対して対話的リベースを使うのがベストです。

The Problem

この例では、機能ブランチで作業していたときに変更または削除したいいくつかのコミットがあるという状況で作業を行います。 git log は次のようになっています。

上の git log から、変更したいコミットが二つあることがわかります。
4a4d705 – このコミットでは誤ってマージの衝突をコミットしてしまいました
6c01350 – このコミットではマージの衝突を削除しました

ここでやりたいことは、4a4d705まで時間をさかのぼり、そのコミットのマージの衝突を削除し、マージの衝突が解決したので6c01350を削除し、もうこのコミットは必要ない、ということです。

  1. 壊れたコミット (マージ コンフリクト) がなくなる
  2. 意味のあるコミットだけが残る。見逃したマージ コンフリクトを修正するだけのコミットはない

解決策

この状況はインタラクティブ リベースにとって良い候補となります。 Scott Chaconは、彼の著書Pro Gitの中で、対話的リベースについて次のように説明しています。 「修正されたものが……それが修正した完全ではないコミットに修正できないことがある。そのコミットはパッチシリーズの中に深く埋もれているからだ。 それこそが対話型リベースの目的なのです。コミットを並べ替えたり編集したり、複数のコミットをひとつにまとめたりすることで、たくさんの , を行った後でそれを使います。」

どのコミットを修正するのか?

対話型リベースを開始するには、どのコミットを修正したいのか Git に伝える必要があります。 これを行うには、変更したいコミットの直前のコミットを参照します。 あるいは、Scott Chacon によれば、「そのままにしておきたい最後のコミット」を参照するのです。

理解を深めるために、この例を見てみましょう。 このコミットを参照する方法は 2 つあります。
SHA-1 による場合 – そのままにしておきたい最後のコミットの SHA-1 は 528f82e ですので、対話的な rebase コマンドにこの値を渡すことができます。
By Index – そのままにしておきたい最後のコミットのインデックス位置は 3 (Git はゼロベースのインデックスを使用しています) なので、HEAD~3 を対話型リベースコマンドに渡すことができます。

Note – 対話型リベースを行うコミットが数少ない場合、おそらくほとんどの人はインデックスを使う方が簡単だと思われます。 しかし、多くのコミットがある場合は、SHA-1 を使用する方が簡単でしょう。

Start interactive rebasing

今回の例では、

$ git rebase -i 528f82e

または

$ git rebase -i HEAD~3

を実行すると Vim でこのウィンドウが表示されるでしょう。

git logとは逆の順番でコミットされていることに注意してください。 git log では、最新のコミットが一番上にあります。 このビューでは、最新のコミットが一番下にあります。

Vim を知らない場合は、編集したい単語 pick をクリックし、<i> キー (挿入モード) を押してください。

この例では、変更したいコミットを edit に、削除したいコミットを drop に変更しました。

Amend the commit

ターミナルに戻ると、このようなメッセージが表示されます:

これは、4a4d705 で停止していることを意味します。 このコミットは、変更したい一連のコミットの中で最も古いものです。 このコミットから始めて、最新のコミットまで順番に作業していきます。

注意として、4a4d705 は私たちが誤ってコミットしてしまったマージの競合があるコミットです。

それで、ファイルのマージ競合を修正しましたが、次はどうしたらいいのでしょうか? 迷ったら、git status:

Cool! これは実際に役に立ちますね。 現在 4a4d705 を編集中であることがわかり、このコミットの次に処理される 2 つのコミットが表示されています。

残りのメッセージは、おなじみのワークフローを説明してくれています。 Git は、もしコミットを修正したいのなら git commit --amend を実行するよう指示しています。 これは基本的に、通常のワークフローで使う典型的な git commit のような役割を果たすものです。 このメッセージの下部には、先ほどマージコンフリクトを解消するために行った変更を反映してファイルが変更されたことが表示されます。 コミットする前に、ファイルをステージングする必要があります。 これは通常のワークフローと変わりません。

私たちが行うことは、編集したファイルを git add tempChanger.js でステージし、次に git commit --amend でステージされたファイルをコミットすることだけです!

コミットメッセージを編集するか、そのままにするか、どちらかです。 コミットメッセージをそのままにすることを選択し、:wqを入力して保存し、ウィンドウを終了します。

これで古いコミットを編集しました。 さて、次はどうするのでしょう? git status:

Continue interactive rebase

他に変更するコミットはないので続けましょう!

git rebase --continueを実行すると次のメッセージが表示されます:

おぉ!もう終わりですか!? しかし、他の二つのコミットはどうでしょうか? さて、次に処理されるコミットは 6c01350 です。 このコミットは、対話型リベースを開始したときに削除するようにマークしました (drop) 。 Git はこれを自動的に削除し、次のコミットである 41aa9d2 に移りました。 このコミットは最初の対話型リベースでは一度も変更されていません。 デフォルトのコマンドは pick で、これはこのコミットが使われることを意味します。 Git はこのコミットを適用し、これが最後のコミットなので対話型リベースは完了しました。

注意:もし編集するコミットがまだあったなら、単に次のコミットに移動して上でやったように修正作業を始めたことでしょう。

イジェクトボタン

対話型リベースの途中で失敗し、それを修正する方法がわからない場合、いつでも中断できることは注目に値します。 ターミナルで git rebase --abort を実行すると、 変更を保存しないまま対話型リベースを中止することができます。

After interactive rebase

Our git log now looks like:

The few things are changed from before we started the interactive rebase:

  • we longer have the commit 6c01350 with commit message “Remove merge conflict”.あなたは、私たちがインタラクティブリベース前に行ったことからいくつかの点が変わったことに気付くことでしょう。
  • 編集したコミット 4a4d705 の SHA-1 は 2b7443d です。
  • 元の git log からの最新のコミット 41aa9d2 も新しい SHA-1 で 2b95e92 となっています。 このコミットは変更されたのではなく、その前のコミットに適用されただけです 2b7443d.

Side effects of interactive rebasing

git log の最新の二つのコミットは、新しい SHA-1 を持っているので Git はそれらをまったく新しいコミットとして見なします。 最後のコミットである 2b95e92 についても同様で、コミットメッセージもファイルもまったく変更されていません。 ここで、対話的なリベースに関する重要なポイントが浮かび上がってきました。 あるコミットを変更した場合、そのコミットとそれに続くすべてのコミットは新しい SHA-1 を持ちます。

あなたが変更したコミットがリモートブランチにプッシュされていなければ、これは何の影響も及ぼさないでしょう。 しかし、もし実際にリモートブランチにプッシュされているコミットに対して対話的リベースを行い、自分のブランチを再びプッシュしたとすると、次のようになります。

技術的には git push --force でこれを回避することができますが、これは非常に危険なことです。

別の解決策としては、git push --force-with-lease を使うと自分のコミットだけを変更し、他の人のコミットは変更しないようにできますが、これにも問題があります。 たとえば、新しい SHA-1 が設定されたコミットを他の開発者がすでに自分のローカル ブランチに持っている場合、リモート ブランチをプルすると、これらのコミットとの間でマージ コンフリクトが発生します。 git push --force-with-lease についてはこちらを参照してください。

このセクションから得られる重要なことは、まだリモートブランチにプッシュされていないコミットに対して対話型リベースを使用する方がはるかに簡単で安全だということです。 Originally posted on Dev.to

Senior, Lead, or Principal developer in NYC? Strideが募集しています。 あなたの技術チームをレベルアップさせたいですか? 私たちがどのように行っているかを見てください! www.stridenyc.com

Tags

Join Hacker Noon

無料アカウントを作成してカスタム読書体験をロック解除する。

Leave a Reply