さて、フィリップの答えに基づいて、グラフト、置換、およびフィルターブランチについて少し調査しました。
私が達成したいのは履歴を書き換えることなので、そもそもリポジトリを正しくレイアウトしたふりをして、これを行う方法は、各ブランチの先頭を前のブランチの先端に移植することであると判断しました。次に 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