これを達成するには 2 つの手順があります。
- 新しい空のコミットを作成する
- この空のコミットから開始するように履歴を書き換えます
便宜上、新しい空のコミットを一時的なブランチに置きますnewroot
。
1.新しい空のコミットを作成します
これを行う方法はいくつかあります。
配管だけを使用
最もクリーンなアプローチは、Git の配管を使用してコミットを直接作成することです。これにより、作業コピーやインデックス、チェックアウトされたブランチなどに触れることを回避できます。
空のディレクトリのツリー オブジェクトを作成します。
tree=`git hash-object -wt tree --stdin < /dev/null`
コミットをラップします。
commit=`git commit-tree -m 'root commit' $tree`
それへの参照を作成します。
git branch newroot $commit
もちろん、シェルを十分に理解している場合は、手順全体をワンライナーに再配置できます。
配管なし
newroot
通常の磁器コマンドでは、正当な理由もなく、ブランチをチェックアウトし、インデックスと作業コピーを繰り返し更新しない限り、空のコミットを作成できません。しかし、次のほうが理解しやすいかもしれません。
git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'
--orphan
へのスイッチがない非常に古いバージョンの Gitcheckout
では、最初の行を次のように置き換える必要があることに注意してください。
git symbolic-ref HEAD refs/heads/newroot
2.この空のコミットから開始するように履歴を書き換えます
ここには 2 つのオプションがあります。リベース、またはクリーンな履歴の書き換えです。
リベース
git rebase --onto newroot --root master
これには、単純さの利点があります。ただし、ブランチの最後のコミットごとにコミッター名と日付も更新されます。
また、いくつかのエッジケースの履歴では、何も含まれていないコミットにリベースしているにもかかわらず、マージの競合が原因で失敗することさえあります。
履歴書き換え
よりクリーンなアプローチは、ブランチを書き直すことです。とは異なりgit rebase
、ブランチが開始するコミットを調べる必要があります。
git replace <currentroot> --graft newroot
git filter-branch master
明らかに、書き換えは 2 番目のステップで行われます。説明が必要な最初のステップです。git replace
つまり、置き換えたいオブジェクトへの参照が見つかった場合は常に、Git は代わりにそのオブジェクトの置き換えを調べる必要があることを Git に伝えます。
スイッチを使用する--graft
と、通常とは少し異なることを伝えます。あなたはまだ置換オブジェクトを持っていないと言っていますが、<currentroot>
コミットオブジェクトをそれ自体の正確なコピーで置き換えたいと思っていますが、置換の親コミットはリストしたものでなければなりません(つまり、newroot
コミット)。次にgit replace
、このコミットを作成し、そのコミットを元のコミットの代わりとして宣言します。
ここで を実行するgit log
と、すでに希望どおりに見えることがわかります。ブランチは から始まりnewroot
ます。
ただし、git replace
実際には履歴を変更しないことに注意してください。また、リポジトリから伝播することもありません。あるオブジェクトから別のオブジェクトへのローカル リダイレクトをリポジトリに追加するだけです。これが意味することは、この置換の効果を他の誰も見ないということです – あなただけです.
だからこそfilter-branch
ステップが必要なのです。git replace
ルートコミットの親コミットが調整された正確なコピーを作成します。git filter-branch
次に、後続のすべてのコミットに対してもこのプロセスを繰り返します。それは、歴史を共有できるように実際に書き換えられる場所です。