これを達成するには2つのステップがあります。
- 新しい空のコミットを作成する
- この空のコミットから開始するように履歴を書き換えます
newroot
便宜上、新しい空のコミットを一時的なブランチに配置します。
1.新しい空のコミットを作成する
これを行うにはいくつかの方法があります。
配管だけを使う
最もクリーンなアプローチは、Gitのplumbを使用して、直接コミットを作成することです。これにより、作業コピーやインデックス、またはチェックアウトされているブランチなどに触れないようにします。
空のディレクトリのツリーオブジェクトを作成します。
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
への切り替えがないGitの非常に古いバージョンではcheckout
、最初の行を次のように置き換える必要があることに注意してください。
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
その後、次のすべてのコミットについてもこのプロセスを繰り返します。ここで、履歴を実際に書き換えて、共有できるようにします。