web-dev-qa-db-ja.com

大きなGitブランチを多数の小さなブランチに分割するにはどうすればよいですか?

SVNからGitにインポートしましたが、次のような大きなブランチが1つあります。

  • 機能Cに取り組む
  • 機能Bに取り組む
  • 機能Cに取り組む
  • 機能Cに取り組む
  • 機能Bに取り組む
  • 機能Aに取り組む

A、B、Cの個別の機能ブランチが必要です。私は新しいブランチへのコミットを選択していますが、元のブランチからそれらを削除するわけではないため、どのブランチをプルしたかを手動で追跡する必要があります。

分割する約800のコミットと、おそらく50の機能/バグ修正があります。

私が引き出したものをこのようにgitログに何らかの形で反映させておくといいでしょう。これは可能ですか?

プルしたコミットをスキップして、ブランチ全体をリベースできますが、これにより多くの競合が発生するのではないかと心配しています。コミットをプルするたびに500件の競合を解決したくありません。

進捗状況を追跡しながら、1つのuberブランチから小さな機能ブランチにコミットを引き出す最善の方法は何ですか?

30
Michael Parker

この場合、私はinteractive rebaseを使用します。

HEADでブランチAB、およびCを作成します。また、問題が発生して元のbackupを戻す必要がある場合に備えて、「backup」ブランチを作成します(HEADという名前にすることもできます)。

git branch feature-a
git branch feature-b
git branch feature-c
git-branch backup-before-rebase

それから、あなたが彼らに始めて欲しいコミットでブランチを作成します、多分便利な安定したコミットで。それをnew_trunkなどと呼んでください。

git checkout HEAD~50       ## this will be the new tree-trunk
git branch new_trunk

次に、インタラクティブrebasesを実行し、そのブランチに保持するコミットを選択します。このように使用すると、基本的にはcherry-pickingの一括処理のようになります。

git checkout feature-a
git rebase -i new_trunk    ## -i is for "Interactive"

完了したら、new_trunkから始まる個別の履歴を持つ3つのブランチと、必要な場合は古いbackupを反映するHEADブランチが必要です。

29
willoller

個人的には、このような大幅な変更の長所と短所を本当に検討します(既にこれを行っている場合は、もう一度)。競合(これは、大きなリベース/チェリーピックで煩わしく、それ自体で解決するのが難しい)に遭遇した場合、機能を「マスター」ブランチにマージするときにおそらく困難な時期になるでしょう。

ビッグブランチをフリーズし、「完了」(または「十分」)して、新しい機能ブランチを作成する方が良い/簡単ではないでしょうか。 (または一部のブランチのみを除外しますか?)

しかしあなたの質問には:

変更の追跡/コミットの欠落を自動的に追跡するには、git cherryコマンドを使用します。

git cherry featureBranch bigBranch

機能ブランチのチェリーピックまたはリベース中に競合が発生しなかった場合は、追加のパイプを使用して以前のコードを使用できます。

git cherry featureBranch bigBranch | awk '{ print "pick " $2 }' | tee remaining

これは、featureBranchで欠落しているコミットを印刷(および「残り」と呼ばれるファイルに保存)します。これをbigBranchのインタラクティブなリベースに追加して、不要なコミットを破棄できます。 (おそらく、「ed」エディターをgitエディターとして使用して、インタラクティブなリベースの標準入力にコマンドを渡すことで、さらにスクリプトを作成できますが、私は試していません。)

9
Josef

単純化するために willollerの答え をさらに、

機能のブランチを作成し、必要に応じてバックアップします

git branch feature-a
git branch feature-b
git branch feature-c
git branch backup-before-rebase

次に、機能ブランチをチェックアウトし、開始するコミットからインタラクティブなリベースを実行します

git checkout feature-a
git rebase -i <safecommit>
enter code here

一部の機能ブランチでコミットを共有してツリーをクリーンに保つ場合は、最初に後の機能ブランチを作成しないでください。リベースされた機能ブランチを取得したら、次のように共有コミット参照を使用しますsafecommit

#on branch feature-a
git checkout -b feature-d
git rebase -i <sharedcommit>
4
r0hitsharma

私が見つけたもう一つの方法は、 "git notes"を使うことです。

http://alblue.bandlem.com/2011/11/git-tip-of-week-git-notes.html

この機能により、実際にブランチを変更したり、リベースを必要としたりせずに、既存のコミットにコメントを追加できます。引き出されたコミットを追跡する1つの方法は、それぞれにgit noteを追加することです。

Cherry-picked to features\xyz 925a5239d4fbcf7ad7cd656020793f83275ef45b

これは、大部分が手動のプロセスで役立ちます。特定のブランチへのコミットを選択する小さなスクリプトを記述して、関連するgitノートを元のコミットに戻すことができます。

または、本当にファンキーになりたい場合は、次のようにしてプロセス全体を自動化できます。

  1. すべてのコミットにgit noteを追加して、どの機能ブランチに選択したいかを伝えます:TOCHERRYPICK: features\xyz
  2. すべてのgitノートをスキャンするスクリプトを記述し、すべての機能ブランチを自動的に作成し、選択した正しいコミットを適切に選択します。次に、gitノートをCHERRYPICKED: features\xxx at 925a5239d4fbcf7ad7cd656020793f83275ef45bに変更して、ツールを後で再実行して、より多くのコミットを選択できるようにします。
  3. コミットが選択されたときに目立つようにしたい場合は、同様の名前のタグの作成を自動化することもできます:CHERRYPICKED:<branch>:SHA
2
Michael Parker

分割する必要のあるコミットの膨大なリストがなく、それらが非常に独立した機能でない限り、つまり、解決すべき競合がある同じ行を変更しない限り、私はこれを正直に行いません。

他の人が提案したように、機能ごとに新しいブランチを作成し、git rebase --interactiveを使用して目的のコミットを含めます。

迷子にならないようにするには、git-rebase-todoファイルの内容を

  • 必要なすべてのコミットのリストを編集し、機能別に分類する
  • コミットのリストを個別のファイルに分離する

次のようなコマンドを使用して、コミットのリストを作成できます

git log --oneline --reverse  44e19^... > log.txt

コミット44e19以降を表示します。これはあなたにこのようなファイルを与えます

44e1936 dSRGratuities (SummaryRecord)
67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
69d70e2 Receipt Report: Payment
....

編集すると(分類を追加するために、機能a、b、cなど)、私のsorted.txtのようになります。

c 44e1936 dSRGratuities (SummaryRecord)
a 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
b 69d70e2 Receipt Report: Payment
c abea7db Receipt Report: Cashback
a cf96185 Receipt Report: Gratuity
c 70e987a Receipt Report: use amount tendered for printing
a 7722ac8 Receipt Report: use amount tendered for calculations
c 47f1754 Receipt Report: store amount tendered
b b69a73f Receipt Report: Use enum Paym_FieldCount
a 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
c ad67e79 Use SharpReport enum
b 3c510c6 enum SharpReport
a e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
b 4e0c3e4 m_Gratuities m_szGratuities (SalesSummaryRecord)
b bd054f7 _gx_fn_Cashback

次に、お気に入りのスクリプト言語でスクリプトを作成し、並べ替えられたリストをgit-rebase-todoファイルのコレクションに変換します。あなたのスクリプトは私が書いたばかりのものに似ているかもしれません。

foreachline text sorted.txt {
    set fields  [split $text { }]
    set branch  [lindex $fields 0]
    set commit  [lindex $fields 1]
    set comment [string range $text 10 end]
    set command "echo pick $commit $comment"
    exec cmd /S /C $command >> $branch.txt
}

スクリプトは、コミットソートファイルを1行ずつ読み取り、スペース文字{}で分割して、2つのフィールドbranchcommitを取得し、説明のために部分文字列(文字10以降)を取得しますコミット。説明は必須ではありませんが、人間が間違いをチェックするのに役立ちます。

次に、適切なgit-rebase-todoファイルに1行を入れ、機能ごとに1つのファイルを作成します。私は、非常に見苦しいWindows echo string >> fileコマンドを実行してこれをハッキングしました。

これにより、いくつかのファイルが作成されます。私のファイルa.txt

pick 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
pick cf96185 Receipt Report: Gratuity
pick 7722ac8 Receipt Report: use amount tendered for calculations
pick 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
pick e470e07 m_Gratuities m_dSSGratuities (SalesSummary)

全体が醜いです。あなたがそうする必要があり、スクリプトを書くのが上手でない限り、私はそれをお勧めしません。


先ほど、上のテキストを書いて、少し考え直しました。上記では、これは多くの作業であり、実行する価値がないことをほのめかしましたが、それ以来、誰かが上記を実行したように見え、非常に価値がある状況を見てきました。

Visual Studio for MFC/C++のリリースを覚えています。新しいリリースごとに、コンパイラの変更、IDEの変更、MFCの改善、およびそれ以降のバージョンのWindowsでの実行が行われます。これは、コンパイラーをVS6およびWindowsから遠ざけるXPコンパイラーを満たすために言語の変更、MFCを満たすための関数呼び出しの変更などが必要になる場合があります。

ここで、MicrosoftがVisual Studioの開発中に毎週バックアップを取り、誰かが規則的に古いバックアップを取り、コードの変更をGitのようなバージョン管理システムにコミットしたとします。次に、変更の分類を開始しました...

  • a。 =コンパイラの変更
  • b。 =ライブラリの変更
  • c。 = IDE変更
  • d。 =セキュリティの改善

    等.

Microsoftはこれらのそれぞれにブランチを作成し、最新かつ最高のIDE(cを含む)を持ち始め、最新のWindowsで実行され、古いレガシープログラムをコンパイルすることができます言語(aなし)とライブラリ(bなし)を使用して作成された。

以前はレガシーソフトウェアに縛られていた開発者は、論理的かつ段階的に改良を加えることができます。言語の変更とライブラリの変更は互いに独立しており、すべての中間バージョンを通過する必要なく、最新かつ最高のVisual Studioでそれを実行します。

  <LanguageStandard>stdcpp14</LanguageStandard>

これは何が起こったのかと言っているわけではありませんが、Visual Studioの最近のバージョンは、レガシプログラムを破棄して(決して)書き換えるのではなく、更新できるようにした方がはるかに優れているようです。古いソフトウェアの変更をバージョン管理し、論理ブランチに整理するためです:コンパイラバージョン、DLL /ライブラリバージョン。

したがって、膨大な数の古いコミットを個別のブランチに分割することが価値がある場合があることを確認できます。

Visual Studio 2019では、行を追加できます

<PlatformToolset>v141_xp</PlatformToolset>

vS 2015およびVS 2017とのコンパイルとリンクに失敗した古いWindowsプログラムのコンパイルと実行を管理ファイルに追加します。Microsoftの誰かがパフォーマンスとセキュリティの改善を古いソフトウェアにリベースしているように見えますが、 breaking changesは、近代化に伴うことがよくあります。

2
Ivan