2

しばらく前にプロジェクト用のプライベート git リポジトリを作成し、メジャー バージョン リリースごとにメンテナンス ブランチを作成するパターンを開発しました。

プロジェクトの数か月後、古いバージョン用のブランチがいくつかありますが、それらはもはやサポートされていません。これは問題を処理するための厄介な方法であることに気付きました。より整然とした代替手段として、代わりに個々のバージョンのタグを使用して、開発ブランチとリリース ブランチを維持したいと考えています。

理想的には、現在のリポジトリをこの新しい形式に変換したいと考えています。リリース コミットとマスターでのコミットの関係については、コミット履歴をできるだけ残しておきたいのですが、すべてのリリース ブランチを 1 つのリリース ブランチに変換したいと考えています。

望ましいリポジトリ レイアウト - 前後

リポジトリは私だけが使用するので、ブランチの内容を別のブランチの末尾に簡単に貼り付けることができました。ここでは、正確なコミット ハッシュを保持することは気にしませんgit rebase --onto

保存で気になるのはmasterブランチとのマージ履歴です。前のブランチのヒントと、最初にマスターからブランチされたコミットの両方に基づいて、各ブランチのルートコミットを再親化したいと思います-それをマージコミットに変えます。

次に、マスターとそのブランチの間の他の多くのマージを保持したいと思います。これは、チェーンのさらに上で発生しました。

私はgit rebase --onto branchB-divergence...branchA-tip branchB(ドキュメントを調べながら、-mと-iを試すなど、いくつかのバリエーションを試しました)

その結果、誤って master で大量のコミットが複製され、マージ履歴が失われたり、解決が必要なマージ競合が絶えず発生したりしていました。

私が達成しようとしていることは可能ですか?このような一連のコミットを再親化するには、どのような手順に従うのでしょうか?

4

2 に答える 2

2

さて、フィリップの答えに基づいて、グラフト、置換、およびフィルターブランチについて少し調査しました。

私が達成したいのは履歴を書き換えることなので、そもそもリポジトリを正しくレイアウトしたふりをして、これを行う方法は、各ブランチの先頭を前のブランチの先端に移植することであると判断しました。次に git filter-branch を実行して、変更を永続的にします。

新しいワークフローでは、変更が完了してリリースの準備が整うと、リリース ブランチにマージされます。履歴を調べると、これらのマージが行われ、元のブランチ ヘッドが何であれ解決されたように見えるようにしたいと思います。

結果を注意深く見ると、実際にはマージ コミットがないことに気付くでしょう。移植された各「マージ」は、次のコミットに直接つながります。これは、何十もの予備のブランチが浮かんでいることほど大きな問題ではないので、未解決のままにしておきます。



移植 移植前後のハッシュラベル付きコミットツリー

ファイルを作成しました.git/info/grafts。この例では、接ぎ木ファイルに 2 つのエントリがあり、新しいブランチの親ごとに 1 つです。

私が犯した最初の間違いは、コミットの元の親も含めるのを忘れていたことでした.マスターへの私の添付ファイルの半分が消え、気付くのにプロセスの約半分を要しました.

2回目で、グラフトファイルの内容が正しくなりました

[commit] [parent] [parent]
hash2    p2       hash1
hash4    p3       hash3



クリーニング

以前のコミットで削除された追跡されていないファイルが作業ディレクトリに浮かんでしまいました。それらがどのようにそこにたどり着いたかのメカニズムについてはわかりませんが、コミット履歴に保存されていることはわかっているので、作業ディレクトリのコピーを削除して、十分に実行git reset --hardしました。

branch-C はすでに新しいリリース ブランチの先端を指しているので、名前を変更します。

% git branch -m branch-C release

移植プロセスの次のステップは、移植片を永久的なものにすることです。これにはgit filter-branch、コミット ツリーを完全に書き換える必要があります。

このリポジトリを実際に使用しているのは私だけなので、履歴の書き換えは今のところ問題ありません。面白い話ですが、私がレポをクリーンアップしている主な理由は、レポをすぐに他の人と共有することを計画しているためです。歴史。

これらすべてのコミットを再作成するので、古いブランチ ポインターがぶらぶらしたり、古くて死んでいるコミット ツリーを表示したままにしたりしたくありません。

% git branch -d branch-A
Deleted branch branch-A (was hash1).
% git branch -d branch-B
Deleted branch branch-B (was hash3).

グラフトのおかげで、git が文句を言うためのぶら下がっているヒントがないので、削除はスムーズに進みます。

また、リポジトリをオフサイトで同期するので、トラッキング ブランチはこれらの枯れ木も保持します。これは後で で解決する予定push --forceですが、今のところ、変更をローカルで再確認するときに混乱しないように、リモコンをドロップするだけです。

% git remote remove origin



書き換え履歴

さて、考えられないことをする時が来ました。ローカルの私の git リポジトリには正しいブランチ レイアウトがあり、リリース ブランチとマスター ブランチのヒント以外のコミットへのポインタはありません。

release支店を調べました。

引数なしでgit filter-branch、ツリーを下って歴史を書き換え、すべての移植片を永続的にします。

% git filter-branch
Rewrite (...) (73/73)
Ref 'refs/heads/release' was rewritten

まだ、元の計画で必要だった光沢のあるタグを作成していません。これは、タグ ポインターが無効なコミット ハッシュを指していたためです。

結果を調べて、リポジトリが思い通りになったので、grafts ファイルをクリーンアップしてタグを追加します。

.git/info/grafts気にしないコミットを移植しているので、自信を持って、ファイルを完全に削除するか、問題のあるエントリを消去できます。

 % rm .git/info/grafts

コミット ツリーはまだ正しく見えるので、さまざまなリリースに必要なすべてのタグを調べて追加しました。

履歴を書き換える最後のステップがあります。同期したいリモート リポジトリです。

リモートを再追加しています。これにより、コミット ツリーがすべて絡み合って、しばらく病気に見えます。

% git remote add origin (...)

最初は通常git push --force --allの . そのためのオプションがあり、それは--prune.

% git push --force --all
Counting objects: 161, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (61/61), done.
Writing objects: 100% (86/86), 9.06 KiB, done.
Total 86 (delta 48), reused 0 (delta 0)
To (...)
* [new branch]      release -> release

% git push --force --all --prune 
To (....)
 - [deleted]         branch-A
 - [deleted]         branch-B
 - [deleted]         branch-C

すべてが完璧なので、git filter-branch がリリース ブランチ用に作成したバックアップ情報も削除しました。

% rm .git/refs/original/refs/heads/release
于 2013-06-05T03:41:13.617 に答える
1

そのようにしないでください。単に最終的な休息場所である 'LifeSupport'のブランチを作成して--orphanから、それぞれのデッド ブランチをそのブランチにマージし (マージ戦略--ours)、適切なバージョンで最後のライフ サポート コミットのそれぞれにタグを追加してみませんか?番号。そうすれば、古いブランチ ref を削除しても、古いバージョンに戻すことができます。

あるいは、graftsまたはreplace (グラフトは非推奨ですか?)を使用して、古いブランチ シリーズを指定したチェーンに結合します。これらは、 経由で凍結できますfilter-branch

于 2013-06-04T12:30:24.557 に答える