Masterとdevの2つのブランチを持つプロジェクトがあるとします。一度テストするとマスターにマージされる特別なイベントのために、devにたくさんのコミットがあります。次に、イベントが終了した後、イベント固有のコードを削除したいと思います。ただし、イベントコードが追加されてから他のコミットが行われたため、gitリセットは実行されません。
現在、私はgit checkoutを使用して、イベントがマージされる前のファイルをチェックアウトし、次にgit diffを使用して、イベントがコミットされてから行われた変更を再度追加しています。これは私には非常に厄介な方法のように思えます。
プロジェクトに一時的なコードを含めるためのより良い解決策はありますか?
編集:明確にするために、変更をコミット、プッシュ、非コミット、プッシュする必要があります。
マスターを取得してブランチを作成します:git checkout -b special-event
、変更を加え/適用します。イベントが終了したら、マスターに切り替えてブランチを破棄/削除するだけです。
変更を継続するには、マスターで変更を行い、移動しながら特別なブランチにマージします。 git checkout master
...変更を加える...git checkout special-event; git merge master
。
または、1回のコミットですべての特別イベント関連の変更を行い、それらをロールアウトする場合はgit revert
を使用して、そのコミットのみを指定します。
「一時的なコード」? gitではそのためにブランチを使用します。コミットはgitで非常に軽量であり、ブランチは、ほんの少しのロジックがアタッチされたコミットの単なる名前(または参照)であり、他のシステムと比較して非常に軽量です。
ロジックのほんの少しは、参照が最後のコミットに自動的に更新されるということです。これがブランチのほとんどすべてです。つまり、実際には何も作成または削除されないため、gitでブランチを作成および破棄することは、高速でシンプルであり、安全ですらあります。削除後も、commit-idでブランチヘッドを参照できます(はい、ガベージコレクションされるまでそこにあります。それでも、他に参照がない場合にのみ発生します)。
Gitのほとんどすべてのコマンドは、パラメーターとしてコミットへの参照を取ります。これはgitマージにも当てはまります。ブランチをマージするのではなく、コミットをマージします。はい、「git merge」と入力しますが、ここでも、ブランチは単なるコミットの名前です。それ以上のものはありません。また、必要なのはイベントのコミットをグループ化することだけなので、名前を付けるだけです。
したがって、正しいことは、イベントのブランチを作成することです。または、おそらく2つ:「event-master」と「event-dev」。ここで、「event-dev」でイベントのコードを開発します。メインコードで修正する必要のあるバグに遭遇した場合は、通常の「dev」ブランチに隠して切り替え、修正をコーディングしてコミットします。 'event-dev'に戻り、 'dev'からマージして、スタッシュをポップします。完了したら、開発を続け、コミットしてテストします。問題がない場合は、「event-dev」を「event-master」にマージします。これには修正も含まれます。修正はまだ「マスター」にないことに注意してください。
修正を「master」にマージする必要がある場合は、修正が「dev」にあるため、通常の方法で実行します。
基本的に、このセットアップでは次のことができます。
通常どおりメインコードを開発します。「dev」にコミットし、テストして、「master」にマージします。
同様の方法でイベント固有のコードを開発します。「event-dev」にコミットし、テストして、「event-master」にマージします。それはまったく同じワークフローです。
2つのワークフローを混在させます。ブランチをコミットして切り替えるか、gitstashを使用します。
ブランチを(ほぼ)自由にマージします。マスターが何らかの方法で更新され、イベントの変更が必要な場合は、「master」を「event-dev」にマージできます。イベントの変更がどうしても必要で、それらを「マスター」にプッシュする通常のテストサイクルを待つことができない場合は、「dev」を「event-dev」にマージできます。 gitは、マージがクリーンである限り、つまり、2つの-devブランチで同じコードを2つの異なる方法で変更しない限り、これを実行します(もちろん、これは処理する必要がある特殊なケースです)。
さらに柔軟性が必要な場合は、さらにブランチを作成します。柔軟性を高めるために、個々のコミットをブランチに選択することもできますが、一般的にはそれをお勧めしません(自分が何をしているかを本当に理解している場合にのみ実行してください)。
最後に、このワークフローはgitでは非常に自然であることを指摘しておく必要があります。実際、「dev」で開発し、「master」で変更をプルすることは、一般的に言って最高ではありません。開発している機能またはモジュールごとにdevブランチを作成し、それらのブランチを「dev」にマージするのが通例です。
Gitを使用するときの正しい考え方は、「今日はどのようにコーディングしたいですか?機能Xです。ブランチ「feature-x」を作成してハッキングを始めましょう。」だと思います。あなたのその出来事も例外ではありません。
今、私があなたに言っていることは、あなたが最初から物事をどのようにすべきだったかということを知っています、そしてそれは今のところあまり役に立ちません。イベントの変更が 'dev'ブランチへの通常の変更と混合されているため、ツリーを修正する必要があります。したがって、問題は、イベントの変更のみを使用して「event-dev」を適切に作成し、同時に「dev」からそれらを削除する方法です。
歴史を書き換える時が来ました。それがどれほど難しいかは、変更の性質によって異なります。たとえば、すべての変更が1つのディレクトリに属している場合は、作業が簡単になります。
これが私がすることです(これ以上のことはわかりません):
gitlogで履歴を調べます。
最初のイベント固有の変更の直前にあるコミットを見つけ、そのcommit-idに注意してください。これは「day-0」コミットです。
そのコミットを指す「newdev」という名前のブランチを作成します。クリーンツリーでこれを実行します。つまり、これを実行する前にコミットします。gitcheckout <commit-id> -b newdev;
'event-dev'を作成します:git checkout -b event-dev;
これで、両方とも「day-0」コミットを指す2つのブランチができました。
履歴をもう一度見てください(git log dev)。commitごとにそれに従う必要があります。
'day-0'に続く各コミットは、メインコードに属するコミットか、イベントのみに属するコミットのいずれかであると想定しています。あなたがしなければならないのは、正しいブランチでそれらをチェリーピックすることです。メインコードの場合は「newdev」、イベントコードの場合は「event-dev」です。正しい順序で(「0日目」から今日まで)一度に1つずつ実行します。
運が良ければ、「newdev」で終わるコミットは「event-dev」とその逆のコミットに依存しません。あなたはちょっと終わった。現在のmasterとdevの名前をmaster-oldとdev-oldに変更し、次にnewdevの名前をdevに変更し、devからmasterを作成し、event-devからevent-masterを作成すると、設定が完了します。
運が少し悪い場合は、「newdev」を「event-dev」にマージする必要がある場合があります。これは、一部のコミットがメインコードで行われた変更に依存しているためです。ここで大胆に感じているなら、gitrebaseについて読む時が来ました。しかし、必要がない限り、リベースはしないでください。
または(さらに悪いことに)「newdev」の一部のコミットは「event-dev」の変更に依存します...おっと、メインブランチが必要とする場合、そのイベント固有のコードはそれほどイベント固有ではないことがわかります。いくつかのマージが必要です。
または(悪い)1つのコミットに両方の種類の変更が含まれています:分割統治(変更を分離して適切なブランチに適用する必要があります)、つまりコミットを2つに分割します。
または、あなたの木について十分な詳細がないため、今は想像できない何かがあります。
それはそよ風か悪夢かもしれません。事前に各コミットを調べ(git show、パッチとして見ることができます)、何をすべきかを決定します(最終的には、ファイルを編集するだけの方が簡単かもしれません)、わからない場合は、ブランチを作成します、そこで作業し、何が起こるかを確認し、問題がなければマージし、それ以外の場合は削除して、再試行します。
これまでは触れていませんが、もちろん、ツリー全体のコピーを作成し、gitファイルを含めて、100%安全になるようにコピーを処理することができます。
最初からそれを行うのはかなり簡単です。今それを修正します、まあ、頑張ってください。 :)
git checkout -b event
...特定のイベントを変更します...
git commit -am "specific event change"
...別の特定のイベントを変更します...
git commit -am "another specific event change"
この時点で、masterブランチはそのままで、イベント固有の変更はeventブランチにあります。 eventブランチでも必要なマスターブランチに変更が加えられた場合は、rebase..を使用します。
git rebase master
別の回答は、masterをeventにマージすることを提案しましたが、rebaseは通常より良いアプローチです。 rebaseは、トピックブランチで行われたコミットを切り離し、更新されたmasterを前方にプルしてから、トピックブランチの変更を再適用します上に...トピックブランチの変更がマスターの最新バージョンに加えられたかのように。
シナリオでは、イベントが終了したら、eventブランチを削除するだけです。
私の特許を取得していない方法に従ってコミットをロールアップします。
# work on a new branch
git checkout -b event-36
git commit -a -m "all broken dammit"
git commit -a -m "fixed that damn code"
git commit -a -m "almost ready, going to eat lunch"
git commit -a -m "It's done!"
# other people might be working on master in the meantime, so
git checkout master
git checkout -b erasemeImmediately
git merge event-36
git reset --soft master # THE KEY TO THE WHOLE THING: SOFT RESET!
git commit -a -m "Event 36, all code in one commit"
git checkout master
git merge erasemeImmediately
これはreflog
で行うことができますが、その場合は最近のCSの学位が必要になります(つまり、理解するのが難しい)。
これで、コミットは1つになります。これで、revertを使用するか、それなしでブランチへの道をチェリーピックすることができます。
私の経験では、いくつかの特別なイベントには繰り返し発生する方法があります。したがって、ここで検討する別の解決策は、特別なイベントの処理を有効にする構成オプションを作成して、必要に応じてオンとオフを切り替えることができるようにすることです。
git revert
コミット、または元に戻す必要のあるコミットの範囲が削除されます。公開リポジトリにプッシュすることも安全です。