以前、どのようにすればよいか尋ねました最初の2つのコミットを圧縮するGit リポジトリ内。
これらの解決策は非常に興味深く、git の他の部分ほど頭を悩ませるものではありません。しかし、プロジェクトの開発中に何度も手順を繰り返す必要がある場合は、やはり少々面倒です。
したがって、私は一度だけ苦労して、その後は標準の対話型リベースを永久に使用できるようにしたいと考えています。
そこで私がやりたいのは、最初のコミットとなるためだけに存在する空の初期コミットを持つことです。コードも何もなし。リベースのベースとなるようにスペースを占有するだけです。
そこで私の質問は、既存のリポジトリがある場合、最初のコミットの前に新しい空のコミットを挿入し、他のすべてのコミットを前に進めるにはどうすればよいかということです。
ベストアンサー1
これを実現するには 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
スイッチがない非常に古いバージョンの 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 がそのオブジェクトの置き換えを調べるように指示するものです。
スイッチを使用すると--graft
、通常とは少し異なることを伝えます。まだ置換オブジェクトがないが、<currentroot>
コミット オブジェクトをそれ自体の正確なコピーで置換したいが、置換の親コミットはリストしたもの (つまり、コミットnewroot
) である必要があります。次に、git replace
このコミットを作成し、そのコミットを元のコミットの置換として宣言します。
ここで を実行するとgit log
、すでに希望どおりになっていることがわかります。つまり、ブランチは から始まりますnewroot
。
ただし、git replace
実際には履歴が変更されるわけではなく、リポジトリ外に伝播されることもありません。リポジトリに、あるオブジェクトから別のオブジェクトへのローカル リダイレクトを追加するだけです。つまり、この置換の効果は他の誰にも表示されず、表示されるのはあなただけです。
そのため、このfilter-branch
手順が必要になります。git replace
ルート コミットの調整された親コミットを含む正確なコピーを作成し、git filter-branch
その後、すべての後続のコミットに対してもこのプロセスを繰り返します。ここで、履歴が実際に書き換えられ、共有できるようになります。