サーチ…


構文

  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
  • git rebase --continue | --skip | --abort | --edit-todo

パラメーター

パラメータ詳細
- 持続するマージの競合を解決した後、リベースプロセスを再開します。
- アボートリベース操作を中止し、HEADを元のブランチにリセットします。リベース操作が開始されたときにブランチが提供された場合、HEADはブランチにリセットされます。それ以外の場合、HEADは、リベース操作が開始されたときの位置にリセットされます。
--keep-empty その結果、親から何も変わらないコミットを保つ。
- スキップ現在のパッチをスキップしてリベースプロセスを再開します。
-m、--merge マージ戦略を使用してリベースする。再帰(デフォルト)マージ戦略を使用すると、リベースは上流側の名前の変更を認識することができます。リベースマージは、上流のブランチの上にある作業ブランチからの各コミットを再生することによって機能することに注意してください。このため、マージの競合が発生した場合、私たちの側は、上流から始まって遠くまでリベースされたシリーズであり、それらのブランチは作業ブランチです。換言すれば、辺が入れ替わっている。
--stat 最後のrebaseからアップストリームに変更されたもののdiffstatを表示します。 diffstatは、構成オプションrebase.statによっても制御されます。
-x、--exec command 対話型のリベースを実行し、各コミットと実行command間で停止する

備考

リベースはリポジトリの履歴を効果的に書き換えます。

リモートリポジトリに存在するリベースコミットは、他の開発者がその開発のためのベースノードとして使用しているリポジトリノードを書き換えることができます。あなたが何をしているのか本当に分かっていない限り、変更をプッシュする前にリベースするのがベストプラクティスです。

ローカルブランチリベース

リベースは、一連のコミットを別のコミットの上に再適用します。

ブランチをrebaseするには、ブランチをチェックアウトし、別のブランチの上にrebaseします。

git checkout topic
git rebase master  # rebase current branch onto master branch

これにより、

      A---B---C topic
     /
D---E---F---G master

に変える:

              A'--B'--C' topic
             /
D---E---F---G master

これらの操作を1つのコマンドにまとめると、ブランチをチェックアウトして直ちにリベースすることができます。

git rebase master topic   # rebase topic branch onto master branch

重要:リベース後、適用されたコミットは異なるハッシュを持ちます。すでにリモートホストにプッシュしたコミットを再配置しないでください。結果はできないかもしれgit pushためにあなたの唯一のオプション残して、リモートホストにローカルのリベース後のブランチをgit push --force

Rebase:私たちと彼らの、ローカルとリモート

リベースは「私たち」と「彼ら」の意味を変えます:

git checkout topic
git rebase   master    # rebase topic branch on top of master branch

HEADの指しているものが "私たち"

リベースが最初に行うことは、 HEADmasterリセットすることです。チェリーピッキングが古いブランチtopicから新しいブランチtopicにコミットする前に(前のtopicブランチのコミットはすべて書き換えられ、別のハッシュによって識別されます)。

マージツールで使用される用語( ローカルリファレンスまたはリモートリファレンスと混同しないでください)に関しては、

=> local is master ("ours"),
=> remote is topic ("theirs")

つまり、マージ/差分ツールは、 localmaster :リベースしているブランチ)と作業ブランチをremoteとして表示します( topic :リベースされているブランチ)

+-----------------------------------------+
| LOCAL:master |    BASE   | REMOTE:topic |
+-----------------------------------------+
|             MERGED                      |
+-----------------------------------------+

イラストレーション

マージ時:

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

私たちは現在の支店のtopic変更しないので、私たちはまだ私たちが取り組んでいるものです(そして私たちは別の支店から合併します)

c--c--x--x--x---------o(*)  MERGE, still on branch topic
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              theirs

リベースの場合:

しかし、リベースでは、リベースが最初に行うことは、上流のブランチをチェックアウトして、その上にある現在のコミットを再生するためです。

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- upstream branch

git rebase upstreamgit rebase upstreamは、まずHEADを上流のブランチに設定します。したがって、前回の現在の作業ブランチと比較して、 '私たち'と '自分のもの'の切り替えが行われます。

c--c--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- set HEAD to this commit, to replay x's on it
               ^       this will be the new "ours"
               |
            upstream      

rebaseは新しい '私たちの' topicブランチで '彼らの'コミットを再生します:

c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
    \
     \
      \--y--y--y--x'--x'--x'(*) <- topic  once all x's are replayed,
               ^                      point branch topic to this commit
               |
        upstream branch

インタラクティブリベース

この例は、対話モードでgit rebaseどのように利用できるかを記述することを目的としています。 git rebaseが何であるか、それが何をするのかを基本的に理解していることが期待されます。

対話型のリベースは、次のコマンドを使用して開始されます。

git rebase -i

-iオプションは対話モードを指します 。対話型のリベースを使用すると、ユーザーはコミットメッセージを変更したり、並べ替え、分割、および/またはスカッシュ(1つに結合)コミットを変更することができます。

最後の3つのコミットを再配置したいとします。これを実行するには、以下を実行します。

git rebase -i HEAD~3

上記の命令を実行した後、テキストエディタでファイルを開き、コミットのリベース方法を選択することができます。この例では、コミットの順序を変更し、ファイルを保存してエディタを閉じます。これにより、適用した順序でリベースが開始されます。 git logをチェックすると、指定した新しい順序でコミットが表示されます。

再コミットメッセージ

さて、コミットメッセージの1つがあいまいであり、それをより説明的にしたいと決めました。同じコマンドを使って最後の3つのコミットを調べてみましょう。

git rebase -i HEAD~3

コミットの順序を並べ替える代わりに、コミットはrewordれます。今回は、デフォルトのpickを変更して、コミット時にメッセージを変更したい場所にrewordします。

エディタを閉じると、リベースが開始され、リワードする特定のコミットメッセージで停止します。これにより、コミットメッセージをあなたが望むものに変更することができます。メッセージを変更したら、エディタを閉じて続行します。

コミットの内容の変更

コミットメッセージの変更に加えて、コミットによって行われた変更を適応させることもできます。これを行うには、1つのコミットに対してeditためにpickを変更しedit 。 Gitは、そのコミットに到達すると停止し、ステージング領域でのコミットの元の変更を提供します。これらの変更は、ステージングを解除したり、新しい変更を加えたりすることで、適応できます。

ステージング領域にコミットに必要なすべての変更が含まれるとすぐに、変更をコミットします。古いコミットメッセージが表示され、新しいコミットを反映させることができます。

単一のコミットを複数に分割する

コミットしたとしますが、後でこのコミットを2つ以上のコミットに分割することを決定しました。以前と同じコマンドを使用して、代わりにeditpickに置き換え、Enterを押します。

さて、gitはあなたが編集用にマークしたコミットで停止し、すべてのコンテンツをステージングエリアに配置します。その時点からgit reset HEAD^を実行して、コミットを作業ディレクトリに置くことができます。次に、ファイルを別の順序で追加してコミットすることができます。最終的に、1回のコミットをn回のコミットに分割します。

複数のコミットを1つにまとめる

いくつかの仕事をして、1回のコミットではないと思われる複数のコミットがあるとします。そのためにはgit rebase -i HEAD~3を実行し、 3を適切な量のコミットに置き換えてください。

今回はpicksquashに置き換えてください。 rebase中に、あなたが押しつぶされるように指示したコミットは、前のコミットの上で押しつぶされます。代わりにそれらを単一のコミットに変えます。

インタラクティブなRebaseを中止する

対話型のリベースを開始しました。コミットを選択するエディタで、何かが間違っていると判断した場合(たとえば、コミットがない、または間違ったリベース先を選択したなど)、リベースを中断したいとします。

これを行うには、すべてのコミットとアクション(つまり、 #記号で始まらない行)をすべて削除すると、リベースが中止されます!

エディタのヘルプテキストは実際にこのヒントを提供します:

# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out

リベース後のプッシュ

ときには、リベースを使ってリライトの履歴を書き直す必要があるかもしれませんが、 git pushは履歴を書き換えたのでそうすることについて不平を言います。

これはgit push --forceで解決できますが、 git push --force-with-lease考慮すると、ローカルのリモート追跡ブランチがリモートのブランチと異なる場合(例えば、誰か)、プッシュを失敗させたいことを示しますそれ以外は最後のフェッチ後にリモートにプッシュされます。これにより、他の誰かの最近のプッシュを誤って上書きすることを防ぎます。

注意git push --force -とさえ--force-with-leaseそのことについては-それはブランチの歴史を書き換えているため、危険なコマンドであることができます。他の人が強制的にプッシュする前にブランチを引っ張った場合、ローカル履歴とリモート履歴が異なるため、 git pullまたはgit fetchにエラーが発生します。これにより、人に予期しないエラーが発生する可能性があります。 reflogを十分に見れば、他のユーザーの作業を回復することができますが、時間が浪費される可能性があります。他のコントリビュータとブランチに強制的にプッシュする必要がある場合は、エラーを処理する必要がないようにコーディネートしてください。

最初のコミットまで下げる

Git 1.7.12以降、ルートコミットにリベースできます。ルートコミットはリポジトリで初めて作成されたコミットであり、通常は編集できません。次のコマンドを使用します。

git rebase -i --root

コードレビューの前にリベース

概要

この目標は、散らばったすべてのコミットをより意味のあるコミットに再編成して、簡単なコードレビューを行うことです。一度に多くのファイルに変更のレイヤーが多すぎる場合は、コードレビューを行うのが難しくなります。時系列的に作成されたコミットをトピックコミットに再編成することができれば、コードレビュープロセスはより簡単になります(そして、おそらくコードレビュープロセスのバグは少なくなります)。

この過度に単純化された例だけでは、gitを使用してコードレビューを改善する唯一の戦略ではありません。これは私がやる方法であり、コードレビューとgitの履歴をより簡単に/より良くする方法を他の人に奨励するものです。

これは一般的にリベースの力を教育的にも示しています。

この例では、対話型のリベースについて知っていることを前提としています


仮定:

  • あなたはマスターのフィーチャーブランチに取り組んでいます
  • あなたの機能は3つの主要な層を持っています:フロントエンド、バックエンド、DB
  • フィーチャーブランチで作業している間にたくさんのコミットを行っています。各コミットは一度に複数のレイヤーに触れる
  • あなたは(最後に)ブランチに3つのコミットしか望みません
    • 1つはすべてのフロントエンドの変更を含む
    • 1つはすべてのバックエンド変更を含む
    • 1つはすべてのDB変更を含む

戦略:

  • 私たちは時系列コミットを「局所的」コミットに変更しようとしています。
  • まず、すべてのコミットを複数の小さなコミットに分割します。各コミットは、一度に1つのトピックのみを含んでいます(この例では、トピックはフロントエンド、バックエンド、DB変更です)
  • 次に、私たちの局所的なコミットを並べ替えて、それらを一回の局所的なコミットにスカッシュします

例:

$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master

これはテキストエディタで表示されます:

pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb

これに変更してください:

e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb

次にgitは一度に1つのコミットを適用します。各コミット後、プロンプトが表示され、次のことができます。

Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
 M db.sql
 M page.html
$ git add db.sql  #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue

その後、コミットごとにこれらの手順を繰り返します。結局、あなたはこれを持っています:

$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql

今度はもう一度rebaseを実行して、並べ替えとスカッシュを実行します。

$ git rebase -i master

これはテキストエディタで表示されます:

pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb

これに変更してください:

pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s  3264de2 adding todo items: page.html

注意:git rebase に、時間順にコミットされた小さなコミットを適用/ 縮退するように指示してください 。さもなければ、虚偽の不要なマージ競合が発生する可能性があります。

そのインタラクティブ・リベースがすべて言われ、実行されると、あなたはこれを得ます:

$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer

要約

あなたは時系列コミットを局所的コミットにリベースしました。現実の生活では、これを毎回行う必要はないかもしれませんが、あなたがこれをやりたい、またはする必要があるときに、今できるのです。さらに、うまくいけば、git rebaseについてもっと学んだことでしょう。

マージの代わりに自動的にrebaseを実行するようにgit-pullをセットアップする

チームがリベースベースのワークフローに従っている場合、 git pull際に、新しく作成された各ブランチがマージ操作ではなくリベース操作を実行するようにgitをセットアップすることが有利かもしれません。

すべての新しいブランチを自動的に.gitconfigするように設定するには、 .gitconfigまたは.git/config次の行を追加します。

[branch]
autosetuprebase = always

コマンドライン: git config [--global] branch.autosetuprebase always

あるいは、-- --rebaseオプションが渡されたかのように常に動作するようにgit pullコマンドを設定することもできます:

[pull]
rebase = true

コマンドライン: git config [--global] pull.rebase true

リベース中のすべてのコミットをテストする

プルリクエストを行う前に、コンパイルが成功し、ブランチ内の各コミットに対してテストが合格していることを確認すると便利です。 -xパラメータを使って自動的に行うことができます。

例えば:

git rebase -i -x make

対話的なrebaseを実行し、 makeを実行makeたびに停止します。 makeが失敗した場合、gitは停止して、問題を修正し、次のものを選ぶ前にコミットを修正する機会を与えます。

オートスタートの設定

Autostashは、ローカル変更にリベースを使用する場合に非常に便利な設定オプションです。多くの場合、上流のブランチからコミットする必要があるかもしれませんが、まだコミットする準備ができていません。

しかし、Gitでは、作業ディレクトリがクリーンでなければ、リベースを開始できません。レスキューへのオートスタート:

git config --global rebase.autostash    # one time configuration
git rebase @{u}                         # example rebase on upstream branch

再起動が完了すると、自動起動が適用されます。リベースが正常に終了したかどうか、または異常終了したかどうかは関係ありません。どちらの方法でも、オートスターシュが適用されます。リベースが成功し、ベースコミットが変更された場合、自動ストッシュと新しいコミットの間に競合が存在する可能性があります。この場合、コミットする前に競合を解決する必要があります。これは、手動で隠してから適用する場合と変わりありませんので、自動的に行うことには欠点はありません。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow