Gitワークフローとリベースとマージの質問


971

私はもう1人の開発者とプロジェクトで数か月Gitを使用しています。私はSVNで数年の経験があるので、私は関係に多くの荷物を持っていると思います。

Gitはブランチやマージに最適であると聞いたことがありますが、今のところ見られません。もちろん、分岐は非常に単純ですが、私がマージしようとすると、すべてが地獄に行きます。今はSVNに慣れていますが、サブバージョン管理システムを別のシステムと交換したようです。

私のパートナーは、私の問題は意気揚々とマージしたいという私の欲求から生じていると私に言います、そして私は多くの状況でマージの代わりにリベースを使用すべきであると言います。たとえば、以下は彼が定めたワークフローです。

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature
git checkout master
git merge my_new_feature

基本的に、機能ブランチを作成し、常にマスターからブランチにリベースし、ブランチからマスターにマージします。ブランチは常にローカルに留まることに注意してください。

これが私が始めたワークフローです

clone remote repository
create my_new_feature branch on remote repository
git checkout -b --track my_new_feature origin/my_new_feature
..work, commit, push to origin/my_new_feature
git merge master (to get some changes that my partner added)
..work, commit, push to origin/my_new_feature
git merge master
..finish my_new_feature, push to origin/my_new_feature
git checkout master
git merge my_new_feature
delete remote branch
delete local branch

2つの本質的な違いがあります(私は思う):リベースの代わりに常にマージを使用し、機能ブランチ(および機能ブランチのコミット)をリモートリポジトリにプッシュします。

リモートブランチについての私の推論は、自分が作業しているときに自分の作業をバックアップしたいというものです。リポジトリは自動的にバックアップされ、何か問題が発生した場合に復元できます。私のラップトップは完全ではありません。したがって、他の場所にミラーリングされていないコードをラップトップに置くのは嫌です。

リベースではなくマージの私の推論は、マージは標準のようであり、リベースは高度な機能のように思われるということです。私の直感は、私がやろうとしていることは高度なセットアップではないので、リベースは不要であるべきだということです。私はGitに関する新しいPragmatic Programmingの本を熟読しましたが、マージについて幅広くカバーしており、リベースについてはほとんど触れていません。

とにかく、私は最近のブランチでワークフローをフォローしていて、それをマスターにマージしようとすると、すべて地獄に行きました。重要ではないはずのこととの衝突がたくさんありました。紛争は私には意味がありませんでした。すべてを整理するのに1日かかり、ローカルマスターはすべての競合を解決したため、リモートマスターに強制的にプッシュすることになりましたが、リモートマスターはまだ満足していませんでした。

このようなものの「正しい」ワークフローは何ですか?Gitはブランチとマージを非常に簡単にするはずであり、私はそれを見ていません。

2011年4月15日更新

これは非常に人気のある質問のようです。最初に質問してから2年間の経験で更新したいと思いました。

少なくとも私たちの場合、元のワークフローは正しいことがわかります。言い換えると、これが私たちが行うことであり、機能します。

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge my_new_feature

実際、生のマージでなくスカッシュマージを行う傾向があるため、ワークフローは少し異なります。(注:これは議論の余地があります。以下を参照してください。)これにより、機能ブランチ全体をマスターでの単一のコミットに変えることができます。次に、機能ブランチを削除します。これにより、ブランチ上で少し厄介な場合でも、マスター上のコミットを論理的に構造化できます。それで、これが私たちがすることです:

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git checkout master
git merge --squash my_new_feature
git commit -m "added my_new_feature"
git branch -D my_new_feature

スカッシュマージの論争 -いくつかのコメント投稿者が指摘したように、スカッシュマージは機能ブランチのすべての履歴を破棄します。名前が示すように、すべてのコミットを1つにまとめます。小さな機能の場合、これを単一のパッケージに凝縮するので、これは理にかなっています。より大きな機能の場合、特に個々のコミットがすでにアトミックである場合、それはおそらく良いアイデアではありません。それは本当に個人的な好みに帰着します。

GithubとBitbucket(その他?)プルリクエスト -マージ/リベースがプルリクエストとどのように関係しているのか疑問に思っている場合は、マスターにマージする準備ができるまで、上記のすべての手順を実行することをお勧めします。手動でgitとマージする代わりに、PRを受け入れるだけです。これはスカッシュマージを行わないことに注意してください(少なくともデフォルトでは)、非スカッシュ、非早送りは、プルリクエストコミュニティで受け入れられているマージ規則です(私の知る限り)。具体的には、次のように機能します。

clone the remote repository
git checkout -b my_new_feature
..work and commit some stuff
git rebase master
..work and commit some stuff
git rebase master
..finish the feature, commit
git rebase master
git push # May need to force push
...submit PR, wait for a review, make any changes requested for the PR
git rebase master
git push # Will probably need to force push (-f), due to previous rebases from master
...accept the PR, most likely also deleting the feature branch in the process
git checkout master
git branch -d my_new_feature
git remote prune origin

私はGitが大好きになり、SVNに戻りたくありません。苦労している場合は、それに固執するだけで、最終的にトンネルの終わりに光が見えます。


31
残念ながら、新しいPragmstic Programmingの本は、ほとんどがSVNで考えながらGitを使用して書かれており、この場合は誤解を招きました。Gitでは、リベースにより、可能な場合は物事がシンプルに保たれます。あなたの経験から、Gitでワークフローが機能しないことがわかります。Gitが機能しないわけではありません。
ポール

18
(svnのように、ここではmergeinfoはなく)何がマージされるかについての情報が保存されないため、この場合はスカッシュマージをお勧めしません。
マリウスK

7
一番下のメモが大好きです。Gitで苦労したのと同じような経験がありましたが、今はそれを使用しないことを想像するのに苦労しています。最後の説明もありがとう、rebase理解に大いに役立ちました
Jon Phenow

6
機能が完成したら、new_featureをマスターにマージする前に、もう一度リベースしてはいけませんか?
softarn-

17
ワークフローは削除されたブランチからすべてのコミット履歴を失います:(
Max Nanasy

回答:


372

「競合」とは、「同じコンテンツの並行進化」を意味します。したがって、マージ中に「すべてが地獄」になる場合は、同じファイルのセットで大規模な進化があったことを意味します。

リベースがマージよりも優れている理由は次のとおりです。

  • ローカルのコミット履歴をマスターの1つで書き換えます(その後、作業を​​再適用して、競合を解決します)
  • 最終的なマージは確かに「早送り」になります。マスターのすべてのコミット履歴に加えて、再適用する変更のみが含まれるためです。

その場合の正しいワークフロー(一般的なファイルセットの進化)が最初にリベースされ、次にマージされることを確認しました。

ただし、ローカルブランチを(バックアップの理由で)プッシュする場合、そのブランチは他のユーザーによってプル(または少なくとも使用)されるべきではないことを意味します(コミット履歴は後続のリベースによって書き換えられるため)。


そのトピック(リベースしてからワークフローをマージする)について、barrapontoはコメントに2つの興味深い投稿(両方ともrandyfay.comから)について言及しています。

この手法を使用すると、作業は常にcurrentで最新のパッチのようにパブリックブランチの上に置かれますHEAD

(同様の手法がバザーにも存在します



2
randyfay.com/node/91randyfay.com/node/89は素晴らしい読み物です。これらの記事により、ワークフローで何が問題になり、理想的なワークフローが何であるかがわかりました。
Capi Etheriel 2011年

簡単に言うと、masterブランチからローカルにリベースすることは、基本的に、マスターが何らかのマージの後に知っていることをローカルが見逃した可能性がある履歴を更新することですか?
ヘラタン

@dtanここで説明するのは、マスターの上にローカルをリベースすることです。ローカル履歴を正確に更新するのではなく、ローカルブランチ内の競合を解決するために、マスターの上にローカル履歴を再適用します。
VonC、2012年

386

TL; DR

Gitのリベースワークフローはで提案されているように、SVNのワークフローに使用されている紛争解決に悪い人かの人からあなたを保護することはできませんA Goryのストーリー:Gitの災害を回避します。競合の解決が面倒になるだけで、不適切な競合の解決からの回復が難しくなります。代わりに、そもそもdiff3を使用して、それほど難しくないようにします。


リベースのワークフローは競合の解決には適していません!

私は歴史を整理するための非常にリベースです。ただし、競合が発生した場合は、すぐにリベースを中止して、代わりにマージを行います!衝突解決のためのマージワークフローの代わりにリベースワークフローを人々が推奨していることは、本当に私を殺します(これがまさにこの質問についてでした)。

マージ中に「すべてが地獄」になると、リベース中に「すべてが地獄」になり、場合によってはさらに地獄にもなります。理由は次のとおりです。

理由#1:コミットごとに1回ではなく1回競合を解決する

マージの代わりにリベースする場合、同じ競合に対して、リベースをコミットする回数まで競合解決を実行する必要があります。

実際のシナリオ

ブランチから複雑なメソッドをリファクタリングするためにマスターから分岐します。私のリファクタリング作業は、リファクタリングとコードレビューの取得に取り組んでいるため、合計15のコミットで構成されています。私のリファクタリングの一部には、以前マスターに存在していた混合タブとスペースを修正することが含まれます。これは必要ですが、残念ながら、マスターでこのメソッドに後で加えられた変更と競合します。案の定、私がこのメソッドに取り組んでいる間、誰かがマスターブランチの同じメソッドに単純で正当な変更を加え、それを私の変更とマージする必要があります。

私のブランチをマスターにマージするときがきたとき、私は2つのオプションがあります:

git merge: 競合が発生します。彼らがマスターし、それを私のブランチ(の最終製品)にマージするために行った変更を確認します。できました。

git rebase:最初のコミット と競合します。競合を解決してリベースを続行します。2回目のコミットと競合します。競合を解決してリベースを続行します。3回目のコミットと競合します。競合を解決してリベースを続行します。4回目のコミットと競合します。競合を解決してリベースを続行します。5回目のコミットと競合します。競合を解決してリベースを続行します。6回目のコミットと競合します。競合を解決してリベースを続行します。私は7番目と衝突しますコミット。競合を解決してリベースを続行します。8番目のコミットと競合します。競合を解決してリベースを続行します。9番目のコミットと競合します。競合を解決してリベースを続行します。10回目のコミットと競合します。競合を解決してリベースを続行します。11番目のコミットと競合します。競合を解決してリベースを続行します。12番目のコミットと競合します。競合を解決してリベースを続行します。13回目のコミットと競合します。競合を解決してリベースを続行します。私は14番目と衝突しますコミット。競合を解決してリベースを続行します。15回目のコミットと競合します。競合を解決してリベースを続行します。

これがあなたの好ましいワークフローであるならあなたは私をからかっていなければなりません。必要なのは、マスターで行われた1つの変更と競合する空白の修正だけであり、すべてのコミットが競合し、解決する必要があります。そして、これは空白の衝突のみの単純なシナリオです。天国では、ファイル間での主要なコード変更を伴う実際の競合が発生することを禁止し、それを複数回解決する必要があります。

必要なすべての追加の競合解決により、間違いを犯す可能性が高まります。しかし、元に戻すことができるので、gitの間違いは問題ありません。もちろん…

理由#2:リベースでは、元に戻すことはできません!

紛争の解決は困難であり、一部の人々はそれが非常に苦手であるということにも、私たちは皆同意できると思います。間違いが起こりやすいため、gitを使用すると簡単に元に戻すことができます。

ブランチをマージすると、gitはマージコミットを作成します。これは、競合の解決がうまくいかない場合に破棄または修正できます。悪いマージコミットをpublic / authoritativeリポジトリにすでにプッシュしている場合でも、を使用git revertして、マージによって導入された変更を元に戻し、新しいマージコミットでマージを正しくやり直すことができます。

ブランチをリベースすると、競合の解決が誤って行われる可能性が高い場合に、あなたはうんざりしています。すべてのコミットに不正なマージが含まれているため、リベース*をやり直すことはできません。せいぜい、戻って影響を受ける各コミットを修正する必要があります。楽しくない。

リベース後、元々コミットの一部であったものや、不適切な競合解決の結果として導入されたものを特定することは不可能です。

* gitの内部ログから古い参照を掘り出すことができる場合、またはリベースの前に最後のコミットを指す3番目のブランチを作成する場合、リベースを元に戻すことが可能です。

紛争解決から地獄を取り除く:diff3を使用

この競合を例にとります:

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

衝突を見ると、各ブランチが何を変更したか、またはその意図が何であったかを知ることは不可能です。これが、私の意見では紛争解決が混乱し、困難である最大の理由です。

救助へのdiff3!

git config --global merge.conflictstyle diff3

diff3を使用すると、新しい競合ごとに3つ目のセクション、つまり共通の祖先がマージされます。

<<<<<<< HEAD
TextMessage.send(:include_timestamp => true)
||||||| merged common ancestor
EmailMessage.send(:include_timestamp => true)
=======
EmailMessage.send(:include_timestamp => false)
>>>>>>> feature-branch

最初に、マージされた共通の祖先を調べます。次に、各側を比較して、各ブランチの意図を判断します。HEADがEmailMessageをTextMessageに変更したことがわかります。その目的は、TextMessageに使用されるクラスを変更し、同じパラメーターを渡すことです。また、機能分岐の目的は、:include_timestampオプションにtrueではなくfalseを渡すことであることがわかります。これらの変更をマージするには、両方の意図を組み合わせます。

TextMessage.send(:include_timestamp => false)

一般に:

  1. 共通の祖先を各ブランチと比較し、どのブランチが最も単純な変更を持つかを判別します
  2. その単純な変更を他のブランチのバージョンのコードに適用して、単純な変更と複雑な変更の両方が含まれるようにします
  3. 変更を一緒にマージしたセクション以外の競合コードのすべてのセクションを削除します

代替:ブランチの変更を手動で適用して解決する

最後に、いくつかの競合は、diff3を使用しても理解するのが大変です。これは特に、diffが意味的に共通ではない共通の行を見つけた場合に発生します(たとえば、両方のブランチが偶然同じ場所に空白行を持っている!)。たとえば、1つのブランチがクラスの本体のインデントを変更したり、同様のメソッドを並べ替えたりします。これらの場合、より良い解決策は、マージのいずれかの側からの変更を調べ、手動で差分を他のファイルに適用することです。

我々は合併シナリオにおける紛争解決される場合がありますどのように見てみましょう競合を。origin/feature1lib/message.rb

  1. 私たちは、現在のブランチをチェックアウト(かどうかを決定しHEAD、または--ours)、または我々はマージ(している支店origin/feature1、または--theirs)を適用する単純な変化です。トリプルドット(git diff a...b)でdiffを使用すると、bからの最後の相違以降に発生した変更が表示されaます。つまり、aとbの共通の祖先をbと比較します。

    git diff HEAD...origin/feature1 -- lib/message.rb # show the change in feature1
    git diff origin/feature1...HEAD -- lib/message.rb # show the change in our branch
    
  2. より複雑なバージョンのファイルを確認してください。これにより、すべての競合マーカーが削除され、選択した面が使用されます。

    git checkout --ours -- lib/message.rb   # if our branch's change is more complicated
    git checkout --theirs -- lib/message.rb # if origin/feature1's change is more complicated
    
  3. 複雑な変更をチェックアウトした状態で、より単純な変更の差分を引き上げます(ステップ1を参照)。この差分からの各変更を競合するファイルに適用します。


4
一度にすべての競合をマージすると、個々のコミットよりもうまく機能しますか?私はすでに単一のコミットをマージすることで問題を抱えています(特に、コミットを論理的な部分に分割せず、検証のための十分なテストを提供しない人々から)。また、バックアップオプションに関しては、リベースはマージよりも悪くありません。インタラクティブなリベースとTortoisegit(含めるコミットの選択を可能にする)などのツールのインテリジェントな使用は、非常に役立ちます。
prusswan

8
#1で理由を説明したような気がします。個々のコミットが論理的に一貫していない場合は、論理的に一貫したブランチをマージして、実際に競合を理解できるようにする必要があります。commit 1にバグがあり、commit 2で修正される場合、commit 1をマージすると混乱します。上で概説したように、15の競合が連続して発生する正当な理由があります。また、リベースが悪化していないというあなたの主張は根拠のないものです。Rebaseは、悪いマージを元の適切なコミットに混合し、再試行するために適切なコミットを残しません。Mergeは行います。
エドワードアンダーソン

6
私はあなたにニルバスに完全に同意します。素晴らしいポスト。それはいくつかのことを明らかにします。ここでは、rerereは役に立ちますか。また、diff3の使用に関する提案に感謝します。今すぐ間違いなくそれをオンにします。
デリック

45
+1だけでdiff3について教えてくれた-共通の祖先が何を言わなければならないのかを教えてくれなかった責任のある人を理解することのできない矛盾の呪いをどのくらいの頻度で見ていましたか。どうもありがとうございました。
John

4
これは受け入れられるべき答えでした。リベースのワークフローは、ある時点でコードベースに大きな相違があったという事実を隠すため、恐ろしいものでもあります。これは、見ているコードがどのように記述されているかを理解したい場合に役立ちます。競合しない小さなブランチのみをマスターにリベースする必要があります。
RobertRüger14年5

32

私のワークフローでは、できる限りリベースします(そして、頻繁にリベースします。差異を累積させないことで、ブランチ間の衝突の量と重大度が大幅に減少します)。

ただし、ほとんどリベースベースのワークフローであっても、マージの場所があります。

マージは実際には2つの親を持つノードを作成することを思い出してください。次に、次の状況を考えます。AとBの2つの独立した機能の境界があり、AとBの両方を確認しながら、機能ブランチCでAとBの両方に依存するものを開発したいとします。

私がすることは、次のとおりです。

  1. Aの上にブランチCを作成(およびチェックアウト)します。
  2. Bとマージします

現在、ブランチCにはAとBの両方からの変更が含まれており、開発を続けることができます。Aを変更した場合、次の方法でブランチのグラフを再構築します。

  1. Aの新しいトップにブランチTを作成する
  2. TとBをマージ
  3. CをTにリベース
  4. ブランチTを削除

このようにして実際にブランチの任意のグラフを維持できますが、親が変更されたときにリベースを行う自動ツールがないため、上記の状況よりも複雑なことはすでに複雑すぎます。


1
リベースするだけで同じことを達成できます。マージはここでは実際には必要ありません(コミットを複製したくない場合を除いて、私はそれを引数としてほとんど見ていません)。
odwl 2009年

1
確かに私はコミットを複製したくありません。作品の機内構成をできる限り綺麗に保ちたい。しかし、それは個人的な好みの問題であり、必ずしもすべての人に適しているわけではありません。
Alex Gontmakher 2009年

最初の段落に100%同意します。(@エドワードの答えはそうではない場合に機能しますが、私はむしろあなたが提案するように世界のすべてのプロジェクトを機能させたいです)。残りの答えは、AとBの進行中にCで作業することはすでにリスクが高い(少なくともAとBに実際に依存している範囲で)ので、結局のところ、おそらくマージを維持しません(Cは最新かつ最高のものの上にリベースします)。
Alois Mahdal、

23

ほとんどすべての状況下でgit push origin --mirrorを使用しないでください。

ローカルボックスにないすべてのリモートブランチが消去されるため、これを実行するかどうかは尋ねられません。確認した方がよいでしょう。

http://twitter.com/dysinger/status/1273652486


6
または、結果がどうなるかわからないことをしないでください。私が管理に使用していたマシン Instructions to this machine may lead to unintended consequences, loss of work/data, or even death (at the hands of the sysad). Remember that you are solely responsible for the consequences of your actions がMOTDにありました。
richo

ミラー化されたリポジトリがある場合に使用します(私の場合、ソースリポジトリのpost-receiveフックで特別なユーザーが実行します)
prusswan

14

説明を読んだ後、1​​つの質問があります。

git checkout master
git pull origin
git checkout my_new_feature

機能ブランチで「git rebase / merge master」を実行する前に?

そのため、あなたの masterブランチは、あなたの友人のリポジトリから自動的に更新されません。あなたはそれでそれをしなければなりませんgit pull origin。つまり、多分あなたは常に変化しないローカルマスターブランチからリベースしますか?そして、プッシュ時刻になると、見たことのない(ローカル)コミットがあるリポジトリをプッシュしているため、プッシュは失敗します。


13

あなたの状況では、あなたのパートナーは正しいと思います。リベースの良いところは、部外者にとって、変更がすべて自分でクリーンなシーケンスで発生したように見えることです。これの意味は

  • 変更は非常に簡単に確認できます
  • あなたは素敵な小さなコミットを作り続けることができますが、それらのコミットのセットを(マスターにマージすることによって)一度に公開することができます
  • パブリックマスターブランチを見ると、さまざまな開発者によるさまざまな機能のさまざまな一連のコミットが表示されますが、すべてが混在しているわけではありません

バックアップのために引き続きプライベート開発ブランチをリモートリポジトリにプッシュできますが、リベースするため、他の人はそれを「パブリック」ブランチとして扱わないでください。ところで、これを行うための簡単なコマンドはgit push --mirror originです。

記事Gitを使用したパッケージングソフトウェアは、マージとリベースのトレードオフを説明するかなり良い仕事をします。コンテキストは少し異なりますが、プリンシパルは同じです。基本的には、ブランチがパブリックであるかプライベートであるか、およびブランチをメインラインに統合する方法に依存します。


1
gitを使用したパッケージングソフトウェアへのリンクが機能しなくなりました。元の回答を編集するための適切なリンクが見つかりませんでした。
Chetan 2014年

にミラーリングしないoriginでください。3番目の専用バックアップリポジトリにミラーリングする必要があります。
ミラル

12

とにかく、私は最近のブランチでワークフローをフォローしていて、それをマスターにマージしようとすると、すべて地獄に行きました。重要ではないはずのこととの衝突がたくさんありました。紛争は私には意味がありませんでした。すべてを整理するのに1日かかり、ローカルマスターはすべての競合を解決したため、リモートマスターに強制的にプッシュすることになりましたが、リモートマスターはまだ満足していませんでした。

パートナーのワークフローでも、提案されたワークフローでも、意味のない競合に遭遇したはずです。あなたが持っていたとしても、提案されたワークフローに従っていれば、解決後に「強制」プッシュは必要ありません。これは、プッシュ先のブランチを実際にはマージしていないが、リモートヒントの子孫ではないブランチをプッシュする必要があることを示しています。

何が起こったのか注意深く見直す必要があると思います。ローカルブランチを作成してから、それをローカルブランチにマージしようとしたポイントの間に、リモートのマスターブランチを他の誰かが(意図的に、または意図的に)巻き戻しましたか?

他の多くのバージョン管理システムと比較して、Gitを使用するとツールとの戦いが少なくなり、ソースストリームの根本的な問題に取り組むことができることがわかりました。Gitはマジックを実行しないため、競合する変更は競合を引き起こしますが、コミットの親子関係を追跡することで書き込みを簡単に実行できるはずです。


あなたは、OPが彼のプロセスで発見されていないリベースまたはミスを持っていることを示唆していますよね?
krosenvold 2009年

8

「あなたが単一の開発者で、ブランチが少ない場合でも、リベースを使用して適切にマージする習慣をつけることは価値があります。基本的な作業パターンは次のようになります。

  • 既存のブランチAから新しいブランチBを作成する

  • ブランチBでの変更の追加/コミット

  • ブランチAからの更新のリベース

  • ブランチBからブランチAへの変更のマージ

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/


7

私が観察したことから、g​​itマージはマージ後もブランチを分離したままにする傾向がありますが、リベースしてマージすると、ブランチが1つのブランチに結合されます。後者の方がはるかにきれいに表示されますが、前者の場合、マージした後でも、どのコミットがどのブランチに属しているかを見つけるのは簡単です。


4

Gitでは「正しい」ワークフローはありません。あなたのボートを浮かぶものは何でも使用してください。しかし、ブランチをマージするときに常に競合が発生する場合は、同僚の開発者とよりよく調整する必要がありますか?2人が同じファイルを編集し続けるように聞こえます。また、空白とsubversionキーワード(「$ Id $」など)にも注意してください。


0

(GitKrakenだけでなく、Intellijとでも、リベースワークフローのみを使用します(GitKrakenだけでなく、Intellijとも最初のワークフローgitkをお勧めします):ブランチがあり、それはマスターから始まり、マスターに戻ります。図がきれいで美しい場合、何も地獄に行くことはありません

ここに画像の説明を入力してください

私のワークフローはあなたのものとほとんど同じですが、小さな違いが1つだけあります。次の理由により、ブランチがの最新の変更に進むsquash前に、ローカルブランチの1つにコミットしrebaseますmaster

rebase各コミットに基づいて動作します

つまり、同じ行を変更する15のコミットがある場合、 master場合、スカッシュしない場合は15回チェックする必要がありますが、最終的な結果は何が重要ですか?

したがって、ワークフロー全体は次のとおりです。

  1. チェックアウトしmasterてプルし、最新バージョンであることを確認します

  2. そこから、新しいブランチを作成します

  3. ここで作業を行うとブランチなので、何回でも自由にコミットしてリモートにプッシュできます。心配する必要はありません。

  4. 誰かが「ねえ、私のPR / MRは承認されました。マスターにマージされました」と言われたら、それらをフェッチ/プルできます。いつでも、またはステップ6で実行できます。

  5. すべての作業を行った後、それらをコミットします。複数のコミットがある場合は、それらを押しつぶします(これらはすべてあなたの作業であり、コード行を変更する回数は関係ありません。重要なのは最終バージョンのみです)。プッシュするかどうかは関係ありません。

  6. にチェックアウトしてmasterpull再び最新のmasterローカルであることを確認してください。ダイアグラムは次のようになります。

ここに画像の説明を入力してください

ご覧のとおり、ローカルブランチ上にあります。これはの古いステータスに由来しますがmastermaster(ローカルとリモートの両方で)同僚の変更に伴い前進しています。

  1. チェックアウトしてブランチに戻り、マスターにリベースします。これでコミットは1つだけになるので、競合を1回だけ解決します(GitKrakenでは、ブランチをドラッグして[リベース]を選択するだけで済みますmaster。これが気に入ったもう1つの理由です)。その後、お気に入り:

ここに画像の説明を入力してください

  1. これmasterで、ブランチの変更と組み合わせて、最新ののすべての変更が完了しました。これでリモコンにプッシュできるようになりました。以前にプッシュしたことがある場合は、強制的にプッシュする必要があります。Gitは単に早送りすることはできないことを教えてくれます。これは正常です。リベースのため、ブランチの開始点を変更しました。しかし恐れるべきではありません。力を賢く使ってください。結局のところ、リモートはブランチでもあるので、master何か悪いことをしても影響はありません。

  2. PR / MRを作成し、承認されるまで待ちmasterます。おめでとうございます!これでmaster、図をクリーンアップするために、にチェックアウトし、変更をプルし、ローカルブランチを削除できます。マスターにマージするときにリモートブランチが削除されない場合は、リモートブランチも削除する必要があります。

最終的な図は再びきれいで明確です。

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.