Open3

Gitの履歴を"切断" と "接続" する

okuokuokuoku

他所のリポジトリに一連のコミットを持っていくために履歴を"切断"したいことがある。

もっと簡単な方法もあるかもしれないが、とりあえず filter-branch ではこれができる。

まとめ

WORKING ブランチが処理後の HEAD を指しているとして、

  • 切断
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --parent-filter \
  'test $GIT_COMMIT = <ルートにしたいコミット> && echo "" || cat' \
  <ルートにしたいコミット>^..WORKING WORKING
  • 接続
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --parent-filter \
  'test $GIT_COMMIT = <ルート> && echo "-p <接続先>" || cat' WORKING

要は、 parent-filterGIT_COMMIT が一致したときに特定の parent を echo するようなスクリプトを渡せば良い。

okuokuokuoku

filter-branch での履歴の切断

あるリポジトリの 22a55b9c403fc3f929cc39727a06e44a7db19715^..58f57cda5a1f5be5de34355764263d3c4bea84fe だけを含む履歴を生成するには:

  1. git branch WORKING 22a55b9c403fc3f929cc39727a06e44a7db19715
  2. FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --parent-filter 'test $GIT_COMMIT = 58f57cda5a1f5be5de34355764263d3c4bea84fe && echo "" || cat' 58f57cda5a1f5be5de34355764263d3c4bea84fe^..WORKING WORKING
  3. git update-ref -d refs/original/refs/heads/WORKING

のようにできる。これにより、ブランチ WORKING22a55b9c403fc3f929cc39727a06e44a7db19715 をroot(最初のコミット)とした履歴に書き換えられる。

(警告 WARNING: Ref 'refs/heads/WORKING' is unchanged は安全に無視できる)

okuokuokuoku

接続

履歴の切断のユースケースとしては、ブランチに対する破壊的な操作 -- git lfs migrate とか git filter-branch とかをインクリメンタルに行うことにある。

例えば、↑で切断した 58f57cda5a1f5be5de34355764263d3c4bea84fe の直前のコミット 58f57cda5a1f5be5de34355764263d3c4bea84fe^ には git lfs migrate を掛けたブランチ FIRST が別に存在したとする:

  1. git branch FIRST 58f57cda5a1f5be5de34355764263d3c4bea84fe^
  2. git lfs migrate import --include=*.sls FIRST

↑ の手順でブランチ WORKINGFIRST.. の履歴のみを含むので、

  • git lfs migrate import --include=*.sls WORKING

として git lfs migrate を掛けた後、

  • git rev-list --reverse --topo-order WORKING | head -1
  • git rev-list --max-count=1 FIRST

として書き換え後のcommitを求め、

  • FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch --parent-filter 'test $GIT_COMMIT = 89f3eb81836abc61220f5735ab7bc82af30e7961 && echo "-p 34a3949c688b39c3a923a3369591d7e4af2214db" || cat' WORKING

のようにしてくっつけることができる。