Git rebase --onto --root で過去の歴史を改変する
あるリポジトリの最初のコミット以前に歴史を継ぎ足したい、という需要があるかもしれません。
Gitならできます、それ。さっそくやってみましょう。
コミットの歴史のイメージ
[ NewDeal first commit ] - [ commit 1 ] - [ commit 2 ] - [ commit 3 ] - [ HEAD ]
↑first commit以前のコミットをNewDealリポジトリに入れ込みたい
リポジトリBの歴史
コミットの歴史のイメージ
[ OldDeal first commit ] - [ commit 1 ] - [ commit 2 ] - ... - [ commit 999 ] - [ HEAD ]
改変後のコミットのイメージ
[ OldDeal first commit ] - ... - [ commit 999 ] - [ HEAD ] - [ NewDeal first commit ] - [ commit 1 ] - ...
具体的なコマンド
$ git clone https://github.com/Roosevelt/NewDeal.git $ cd NewDeal/
・新しいリポジトリにoldという名前でリモートのURLを登録する、これで古いソースを取得できる
・fetchしてソースを取得
・oldという名前でローカルのブランチを作成
$ git remote add old https://github.com/Hoover/OldDeal.git $ git fetch old $ git checkout -b old old/master
・今回のメインのオペレーション、rebaseしてOldDealの尻尾とNewDealの頭をくっつける
・git push -fはこれまでのリポジトリの歴史を完全に書き換えてしまうので、共同開発者がいる場合は気をつけてください*1
$ git rebase --onto old --root master
・大抵の場合rebaseしたあとにmergeが必要だと促されます
・OldDealの尻尾とNewDealの頭をどうつなぐか、その結果を決めるコミットを作れということです
・ちまちま手で直すのは苦痛なので、便利コマンドを紹介
・あと、マージ完了した後にpullとかやるのは絶対にヤメましょう、死にます
$ git checkout --ours (ファイル名) カレントを採用する $ git checkout --theirs (ファイル名) リモートを採用する
・最後に git push -f
・「世界は、再構成される――!」
$ git push -f
*1:というのは、forkしているソースのpull req & mergeができなくなります。rebaseした前後のコードは全く違う歴史だと判断されるようです。