git rebase
とgit merge
の使用が推奨されるのはいつですか?
リベースが成功した後もマージする必要がありますか?
それで、あなたはいつどちらを使いますか?
それは簡単です、あなたがあなたの仕事のために新しい base として別のブランチを使うことをあなたが言うリベースで。
たとえばブランチmaster
があり、新しい機能を実装するためにブランチを作成する場合、それにcool-feature
と名前を付けます。もちろん、マスターブランチはあなたの新しい機能のベースです。
さて、ある時点でmaster
ブランチに実装した新機能を追加したいと思います。 master
に切り替えてcool-feature
ブランチをマージするだけです。
$ git checkout master
$ git merge cool-feature
しかしこのようにして新しいダミーコミットが追加されます、もしあなたがspaghetti-historyを避けたいのであれば rebase :
$ git checkout cool-feature
$ git rebase master
そしてそれをmaster
にマージします。
$ git checkout master
$ git merge cool-feature
今回は、トピックブランチはmasterのコミットと新しい機能のコミットを同じにしているので、マージは早送りになります。
自分の答え 言及 TSamperによる を補完するために、
マージする前にブランチY
の作業をブランチB
の作業に統合するという考えがあるため、マージの前にリベースを行うことは非常に良いことです。
繰り返しますが、マージする前に、yourブランチの競合を解決します(つまり、「最近のブランチから私のブランチで作業をリプレイする」のように「リベース」します)ブランチからのポイントB
)
正しく実行された場合、ブランチからブランチB
への後続のマージは早送りできます。
マージは、宛先ブランチB
に直接影響します。つまり、マージはより簡単になります。そうでない場合、ブランチB
は安定状態に戻るまでに長くなる可能性があります(すべての競合を解決する時間)
リベース後のマージのポイント?
説明する場合、B
をブランチにリベースします。これは、B
からのより最近のポイントから作業をリプレイする機会を得るためですが、ブランチにとどまります。
この場合、「リプレイ」された作品をB
に持ち込むには、まだマージが必要です。
他のシナリオ( 例:Git Ready )は、リベースを介してB
に直接作業を持ち込むことです(これにより、すべてのNiceコミットが保存されるか、それらを並べ替える機会さえ与えられます)インタラクティブなリベースを介して)。
その場合(Bブランチにいる間にリベースする場合)、あなたは正しいです:それ以上のマージは必要ありません:
マージもリベースもしていない場合のデフォルトのgitツリー
リベースにより取得:
その2番目のシナリオは、新しい機能をマスターに戻す方法です。
私のポイントは、最初のリベースシナリオを説明することで、リベースはその予備ステップ(「新しい機能をマスターに戻す」)としても使用できることを全員に思い出させることです。
リベースを使用して、最初にマスターを新機能のブランチに「入れる」ことができます。リベースは、HEAD master
から新機能のコミットを再生しますが、まだ新機能のブランチにあり、ブランチの開始点を効果的に移動しますHEAD-master
への古いマスターコミット。
これにより、yourブランチでの競合を解決できます(つまり、単独で、競合解決ステージに時間がかかりすぎる場合にマスターが並行して進化し続けることができます) )。
次に、マスターに切り替えてnew-feature
をマージします(またはnew-feature
ブランチで行われたコミットを保持する場合は、new-feature
をmaster
にリベースします)。
そう:
master
と見なすことができます。ここでの回答の多くは、マージするとすべてのコミットが1つになるため、リベースを使用してコミットを保存することをお勧めします。 これは誤りです。そして、すでにコミットをプッシュしている場合は悪い考えです。
Mergeはコミットを消去しませんnot。 Mergeは履歴を保存します! (gitkを見てください)Rebaseは履歴を書き換えます。これはプッシュした後の悪いことです。
すでにプッシュした場合は、rebaseではなくmergeを使用してください。
ここにLinus '(gitの著者)がいます 。本当に良い読み物です。または、以下の同じアイデアの自分のバージョンを読むことができます。
マスターでブランチをリベースする:
対照的に、トピックブランチをマスターにマージする:
疑問がある場合は、マージを使用してください。
リベースとマージの唯一の違いは次のとおりです。
つまり、簡単な答えは履歴の表示形式に基づいてリベースを選択するかマージするです。
どの操作を使用するかを選択するときに考慮する必要があるいくつかの要因があります。
もしそうなら、リベースしないでください。 Rebaseはブランチを破壊し、それらの開発者はgit pull --rebase
を使わない限り壊れた/矛盾したリポジトリを持つことになります。これは他の開発者を素早く動揺させる良い方法です。
リベースは破壊的な操作です。つまり、正しく適用しないと、 コミットされた作業が失われたり、他の開発者のリポジトリの一貫性が失われたりする可能性があります。
私は、企業が分岐とマージに対処するために専任スタッフを雇うことができる時代から、開発者全員が参加するチームに取り組んできました。それらの開発者はGitについてあまり知らないし、あまり知りたくありません。これらのチームでは、私は何らかの理由でリベースを推奨するリスクはありません。
一部のチームは、各ブランチが機能(またはバグ修正、またはサブ機能など)を表す機能ごとのブランチモデルを使用します。このモデルでは、ブランチは関連するコミットのセットを識別するのに役立ちます。たとえば、そのブランチのマージを元に戻すことで機能をすばやく元に戻すことができます(公平に言えば、これは稀な操作です)。または2つのブランチを比較してフィーチャを比較する(より一般的)。 Rebaseはブランチを破壊するでしょう、そしてこれは簡単ではないでしょう。
私は、開発者一人当たりブランチモデルを使ったチームにも取り組んできました(私たちは皆そこにいました)。この場合、ブランチ自体は追加情報を伝えません(コミットはすでに作者を持っています)。リベースに害はありません。
差し戻しを元に戻す(元に戻す)のと同様に、差し戻しを元に戻すことは、差し戻しを元に戻すことと比較して、かなり困難および/または不可能です。もしあなたが元に戻ろうとしている可能性があると思うなら、マージを使用してください。
リベース操作は対応するgit pull --rebase
で引っ張られる必要があります。あなたが自分で仕事をしているなら、あなたは適切な時にあなたがどれを使うべきかを思い出すことができるかもしれません。あなたがチームで作業しているなら、これは調整するのが非常に難しいでしょう。これが、ほとんどのリベースワークフローがすべてのマージにリベース(およびすべてのプルにgit pull --rebase
)を使用することを推奨する理由です。
次のようなマージがあるとします。
B -- C
/ \
A--------D
マスターブランチ(A - D)のみのログを見るとBとCに含まれる重要なコミットメッセージを見逃すことになるので、マージはコミット履歴を「破壊する」と言う人もいます。
これが本当なら、私たちは this のような質問はないでしょう。基本的に、( - first-parentを使って)明示的に見ないように頼まない限り、BとCを見ることになります。 。
2つのアプローチは異なる方法でマージされますが、一方が他方より常に優れていることは明確ではなく、開発者のワークフローに依存する可能性があります。たとえば、開発者が定期的にコミットする傾向がある場合(たとえば、仕事から家に移るときに1日に2回コミットするなど)、特定のブランチに対して多くのコミットが発生する可能性があります。これらのコミットの多くは最終製品のようには見えないかもしれません(私は私のアプローチを機能ごとに1、2回リファクタリングする傾向があります)。他の誰かがコードの関連する領域に取り組んでいて、彼らが私の変更をリベースしようとした場合、それはかなり面倒な操作になるかもしれません。
「時間を節約する」ためにrm
をrm -rf
にエイリアスしたい場合は、おそらくリベースが必要です。
いつの日か、私はgit rebaseが問題を解決する素晴らしいツールであるというシナリオに出会うことになると常に思います。 git reflogが私の問題を解決する素晴らしいツールであるというシナリオに出くわすと私が思うのと同じように。私は5年以上前からgitを使ってきました。起きていません。
乱雑な歴史は私にとって本当に問題になったことがない。私は今までの自分のコミット履歴をエキサイティングな小説のように読むだけではありません。私が歴史を必要としている時間の大部分は私がとにかくgit blameかgit bisectを使うつもりです。その場合、マージコミットを持つことは実際に私にとって役に立ちます。マージが私にとって意味のある情報である問題を紹介してくれたからです。
私の一般的なアドバイスはまだ残っていますが、私は個人的にリベースを使うことをやめさせたことを述べる義務を負うことを感じます。私は最近 Angular 2 Material プロジェクトと多くのやりとりをしています。彼らは非常にきれいなコミット履歴を保つためにリベースを使いました。これは、リベースを正しく使用するための優れた例として役立ちます。
マージ手段:自分の変更を送り先にマージする単一の新しいコミットを作成します。
Rebase手段:私の現在のコミットのセットをヒントとして使用して、まったく新しい一連のコミットを作成します。言い換えれば、私がリベースした時点から私が行った変更がどうなったかを計算します。そのため、リベース後には変更を再テストする必要があり、リベース中にはいくつかの衝突が発生する可能性があります。
これを考えて、なぜあなたはリベースしますか?開発履歴を明確にするためだけに。あなたが機能Xに取り組んでいて、それが終わったら、あなたが行った変更をマージしたとしましょう。マージするのではなく、リベースしてマージした場合、宛先の開発履歴には、単一の論理的進行におけるすべての個々のコミットが含まれます。これにより、後で変更を確認するのがはるかに簡単になります。 50人の開発者が常にさまざまな機能をマージしている場合、開発履歴を確認するのがどれほど難しいと思うか想像してみてください。
とは言っても、上流で作業しているブランチをすでにプッシュしているのであれば、リベースするのではなくマージするべきです。上流にプッシュされていないブランチの場合は、リベース、テスト、およびマージを行います。
あなたがリベースしたいと思うかもしれないもう一つの時は上流にプッシュする前にあなたのブランチからコミットを取り除きたい時です。たとえば、次のようにします。初期の段階でデバッグ用コードを紹介するコミットと、それ以降の他のコミットでコードをクリーンアップします。これを行う唯一の方法は、対話式リベースを実行することです。git rebase -i <branch/commit/tag>
UPDATE:Gitを使って非線形履歴をサポートしていないバージョン管理システム(Subversionなど)に接続するときにもrebaseを使いたいと思うでしょう。 git-svnブリッジを使用するとき、Subversionにマージし直す変更がトランクの最新の変更の上にある変更の連続的なリストであることは非常に重要です。これを行うには2つの方法しかありません。(1)変更を手動で再作成する方法、および(2)rebaseコマンドを使用する方法です。
UPDATE2:リベースについて考えるもう一つの方法はそれがあなたの開発スタイルからあなたがコミットしているリポジトリで受け入れられたスタイルへの一種のマッピングを可能にすることです。小さな、小さな塊でコミットするのが好きだとしましょう。タイプミスを修正するためのコミット、未使用のコードを取り除くためのコミットなどがあります。あなたがする必要があることを終えた時までに、あなたは長い一連のコミットを持っています。今コミットしようとしているリポジトリが大きなコミットを奨励しているとしましょう。ですからあなたがしている仕事のためには、1つか2つのコミットを期待するでしょう。どのようにしてコミットの文字列を取得し、それらを予想されるものに圧縮しますか?あなたは対話的なリベースを使って、あなたの小さなコミットをより少ないより大きな塊につぶすでしょう。逆のことが必要な場合も同じです。あなたのスタイルがいくつかの大きなコミットであったとしても、レポは小さなコミットの長い文字列を要求しました。あなたはそれをするのにリベースを使うでしょう。代わりにマージした場合は、コミットスタイルをメインリポジトリに移植しました。開発者が多い場合は、しばらくしてからいくつかの異なるコミットスタイルで履歴をたどるのがいかに難しいかを想像できます。
UPDATE3:Does one still need to merge after a successful rebase?
はい、そうです。その理由は、リベースは基本的にコミットの「シフト」を伴うからです。私が上で言ったように、これらのコミットは計算されます、しかしあなたが分岐の時点から14のコミットを持っていたなら、あなたのリベースで何も問題がないと仮定すれば、リベースは完了です。あなたはリベースの前に枝を持っていました。後に同じ長さの枝があります。変更を公開する前に、まだマージする必要があります。言い換えれば、何度でもリベースします(変更を上流にプッシュしていない場合のみ)。あなたがリベースした後にのみマージします。
マージ/リベースの前
A <- B <- C [master]
^
\
D <- E [branch]
git merge master
の後:
A <- B <- C
^ ^
\ \
D <- E <- F
git rebase master
の後:
A <- B <- C <- D' <- E'
(A、B、C、D、E、およびFはコミットです)
この例とgitに関するもっとよく説明された情報はここで見つけることができます: http://excess.org/article/2008/07/ogre-git-tutorial/
マージは変更を統合するための最も簡単で一般的な方法であることは間違いありませんが、それが唯一の方法ではありません。Rebaseは統合の代替手段です。
より良いマージを理解する
Gitがマージを実行するとき、3つのコミットを探します。
早送りまたはマージコミット
非常に単純なケースでは、2つのブランチのうちの1つはブランチが起こって以来新しいコミットを持っていません - その最新のコミットはまだ共通の先祖です。
この場合、統合を実行するのは簡単です。Gitは、他のブランチのすべてのコミットを共通の先祖コミットの上に追加するだけです。 Gitでは、この最も単純な形式の統合は「早送り」マージと呼ばれます。両ブランチは、まったく同じ履歴を共有します。
統合を行うために、Gitはそれらの間の違いを含む新しいコミット - マージコミットを作成する必要があります。
ヒューマンコミットとマージコミット
通常、コミットは人間によって慎重に作成されます。関連する変更のみをまとめてコメントで注釈を付ける意味のある単位です。
マージコミットは少し異なります。開発者によって作成されるのではなく、Gitによって自動的に作成されます。そして、関連する一連の変更をラップする代わりに、結び目のように2つのブランチを接続することを目的としています。後でマージ操作を理解したい場合は、両方のブランチの履歴とそれに対応するコミットグラフを確認する必要があります。
Rebaseとの統合
このような自動マージコミットをせずに済むことを好む人もいますが、代わりにプロジェクトの履歴を単一の直線で展開したように見せたいと思いますいくつかのポイント。
リベース操作を段階的に見ていきましょう。シナリオは前の例と同じです。ブランチBからブランチAへの変更を統合したいのですが、今度はrebaseを使用します。
これを3つのステップで行います
git rebase branch-A // syncs the history with branch-A
git checkout branch-A // change the current branch to branch-A
git merge branch-B // merge/take the changes from branch-B to branch-A
まず、Gitは、行が分岐し始めた後(共通の先祖コミットの後)に発生したブランチAのコミットをすべて「元に戻します」。しかし、もちろん、それらを破棄することはできません。代わりに、それらのコミットを「一時的に保存される」と考えることができます。
次に、統合したいブランチBのコミットを適用します。この時点では、両方のブランチはまったく同じに見えます。
最後のステップでは、ブランチAの新しいコミットが再適用されます。ただし、ブランチBの統合されたコミットの上に新しい位置に置かれます(これらは再ベースされます)。 結果は開発が一直線に起こったように見えます。結合されたすべての変更を含むマージコミットの代わりに、元のコミット構造が維持されました。
最後に、不要で自動生成されたコミットのないきれいなブランチ branch-A を得ます。
注: git-tower
によって素晴らしい post から取得されました。 rebase
のデメリットも同じ投稿の中でよく読むことです。
この文はそれを得ます:
一般に、両方の長所を活用するには、行ったローカルの変更をリベースすることです。ストーリーを整理するためにそれらをプッシュする前にまだ共有していません。
出典: http://www.git-scm.com/book/en/v2/Git-Branching-Rebasing#Rebase-vs.-Merge
この答えは、 Git Flow を中心に広く方向付けられています。テーブルは、Nice ASCII Table Generator とこの素晴らしいコマンド( エイリアス as git lg
)で生成されました:
git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n'' %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'
履歴ツリーとの整合性を保つために、表は新しい順に並べられています。 git merge
とgit merge --no-ff
の違いも最初に参照してください(通常、git merge --no-ff
を使用すると、履歴が現実に近くなります)。
git merge
コマンド:
Time Branch "develop" Branch "features/foo"
------- ------------------------------ -------------------------------
15:04 git merge features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
結果:
* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
| Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
| Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge --no-ff
コマンド:
Time Branch "develop" Branch "features/foo"
------- -------------------------------- -------------------------------
15:04 git merge --no-ff features/foo
15:03 git commit -m "Third commit"
15:02 git commit -m "Second commit"
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
結果:
* 1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/ Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git merge
vs git rebase
最初のポイント:常に機能を開発にマージし、機能から開発をリベースしないでください。これは、 リベースの黄金律 の結果です。
git rebase
の黄金律は、publicブランチで使用しないことです。
つまり :
どこかにプッシュしたものをリベースしないでください。
私は個人的に追加します:機能ブランチでなく、あなたとあなたのチームが結果を認識している場合を除きます。
したがって、git merge
対git rebase
の質問は、機能ブランチにのみ適用されます(次の例では、--no-ff
は常にマージに使用されています)。より良い解決策があるかどうかはわかりません( 議論が存在する )ので、両方のコマンドの動作のみを提供することに注意してください。私の場合、git rebase
を使用したほうが良い履歴ツリーを生成できます:)
git merge
コマンド:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git merge --no-ff features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
結果:
* c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\ Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | | Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | | Fourth commit - Christophe
* | | 98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \ Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
コマンド:
Time Branch "develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m "Sixth commit"
15:07 git rebase features/foo
15:06 git commit -m "Fifth commit"
15:05 git commit -m "Fourth commit"
15:04 git commit -m "Third commit"
15:03 git commit -m "Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m "First commit"
結果:
* 7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
develop
から機能ブランチへgit merge
コマンド:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m “Sixth commit"
15:08 git merge --no-ff development
15:07 git merge --no-ff features/foo
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
結果:
* 9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\ Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* | 5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | | Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ / Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git rebase
コマンド:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10 git merge --no-ff features/bar
15:09 git commit -m “Sixth commit"
15:08 git rebase development
15:07 git merge --no-ff features/foo
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
結果:
* b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/ Fourth commit - Christophe
* 856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git cherry-pick
特定のコミットが1つだけ必要な場合、git cherry-pick
はニースのソリューションです(-x
オプションは、「(コミットから選択されたチェリー...)」という行を元のファイルに追加しますメッセージ本文をコミットするので、通常はそれを使用することをお勧めします-git log <commit_sha1>
表示するには):
コマンド:
Time Branch “develop" Branch "features/foo" Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10 git merge --no-ff features/bar
15:09 git merge --no-ff features/foo
15:08 git commit -m “Sixth commit"
15:07 git cherry-pick -x <second_commit_sha1>
15:06 git commit -m “Fifth commit"
15:05 git commit -m “Fourth commit"
15:04 git commit -m “Third commit"
15:03 git commit -m “Second commit"
15:02 git checkout -b features/bar
15:01 git checkout -b features/foo
15:00 git commit -m “First commit"
結果:
* 50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\ Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| | Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| | Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | Fourth commit - Christophe
* | 1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
First commit - Christophe
git pull --rebase
Derek Gourlay ...よりもうまく説明できるかどうか定かではありません。基本的に、git pull --rebase
の代わりにgit pull
を使用してください:)ただし、この記事で欠けているのは デフォルト :
git config --global pull.rebase true
git rerere
繰り返しますが、 ここ でうまく説明しました。ただし、簡単に言えば、有効にすると、同じ競合を複数回解決する必要がなくなります。
リベースページの本当に良い説明としてのpro git book - 。
基本的にマージは2コミットしてそれらを結合します。
リベースは2の共通の祖先に行き、互いの上に徐々に変更を適用します。これは「よりクリーン」でより直線的な歴史になります。
しかし、あなたがリベースするとき、あなたは前のコミットを放棄して新しいものを作成します。だからあなたは公開されているレポをリベースするべきではありません。レポに取り組んでいる他の人々はあなたを憎むでしょう。
その理由だけで、私はほとんど排他的にマージします。私の支店では99%の差はそれほど変わらないので、競合が発生した場合、それは1つか2つの場所に限られます。
Git rebaseは、履歴内の分岐パスを明確にし、リポジトリ構造を線形にするために使用されます。
リベースして変更をサーバーにプッシュした後、ブランチを削除しても、それまでに作業したブランチの証拠はないため、これはあなたが作成したブランチを非公開にするためにも使用されます。だからあなたの支店は今あなたの地域の関心事です。
リベースを行った後は、通常のマージを実行するかどうかを確認するために使用していた余分なコミットも削除します。
Rebaseコマンドは単にrebase say masterで述べたブランチの上に作業を置き、masterブランチの直接の子孫としてあなたのブランチの最初のコミットをするので、そうです。つまり、このブランチからマスターブランチに変更を反映するために早送りマージを実行できるようになりました。
いくつかの実用的な例は、gerritがレビューと配信の統合に使用される大規模開発に関連しています。
私は自分の機能ブランチを新鮮なリモートマスターに引き上げるときにマージします。これは最小限の作業量の増加をもたらし、例えばgitkの機能開発の歴史をたどるのは簡単です。
git fetch
git checkout Origin/my_feature
git merge Origin/master
git commit
git Push Origin HEAD:refs/for/my_feature
配送コミットを作成するときにマージします。
git fetch
git checkout Origin/master
git merge --squash Origin/my_feature
git commit
git Push Origin HEAD:refs/for/master
配達のコミットが何らかの理由で統合に失敗したときはリベースし、新しいリモートマスターに更新する必要があります。
git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase Origin/master
git Push Origin HEAD:refs/for/master
何をリベースし、何をマージするのかを何度も説明しましたが、いつ何を使うのか?
いつリベースを使うの?
Git rebaseが歴史を変えるように。したがって、他の誰かが同じブランチに取り組んでいるときや、プッシュしているときは、使用しないでください。しかし、ローカルブランチがある場合は、ブランチをマージしてマスターに戻す前にマージリベースマスターを実行して、履歴をきれいにすることができます。こうすると、マスターブランチにマージした後、マスターブランチでブランチを使用したことが見えなくなります - 自動生成された「マージされた..」を持っていなくても履歴は「よりきれい」ですが自動生成された "マージされた.."のコミットなしであなたのマスターブランチの履歴。ただし、git merge feature-branch --ff-only
を使用して、機能をメインにマージするときに競合が発生しないようにして単一のコミットを作成してください。 機能ブランチの履歴を取得するときに作業しているすべてのタスクに機能ブランチを使用しているが、 "マージされた.."コミットではない場合、これは面白いです
2つ目のシナリオは、ブランチから分岐して、メインブランチで何が変わったのかを知りたい場合です。それはすべての単一のコミットが含まれているのでrebaseはあなたに情報を提供します。
いつマージを使うの?
あなたがあなたのマスターブランチにフィーチャーブランチの全ての履歴を持っている必要がないか欲しいとき、あるいは他の人が同じブランチに取り組んでいるとき/あなたはそれをプッシュしました。それでも履歴を残したい場合は、featureブランチをmasterにマージする前にmasterをfeatureブランチにマージしてください。これにより、マスターに機能ブランチの履歴がある場合は早送りマージが行われます(マスターをマージしたために機能ブランチにあったマージコミットを含む)。
例を見てみましょう。 login
ブランチに基づいてmaster
という名前のブランチで作業中に、チームメンバーの1人がmaster
にいくつかの変更をプッシュしました。ブランチのlogin
機能を完了するには、これらの変更が必要です。
図1. master
ブランチでの作業を完了するには、login
ブランチの新しいコミット(EおよびF)が必要です。
Mergingmaster
ブランチを元に戻すと、マージコミットが発生します。これには、両方のブランチ間の変更が含まれ、マージの場所を示すために存在します起こった。
図2. 2つのブランチをマージすると、マージコミットになります。
master
をいつlogin
ブランチにマージしたかを知る必要はありません。代わりに、login
ブランチのすべてのコミットがmaster
ブランチの新しい状態に基づいて行われたふりをしたいと思います。
Gitのrebaseコマンドは、現在のブランチでコミットを一時的に巻き戻し、他のブランチからコミットをプルし、巻き戻されたコミットを先頭に再適用します。電流を切り替えることにより、現在のブランチのベースが他のブランチになります。
図3. login
ブランチの上にあるmaster
ブランチからコミットをリベースして適用します。
ソースは here です