こんな多段操作をするしかないのか?するしかありません

gitの概念を考えてみれば、 こういう操作しか出来ないだろうと納得できます。 できますが、まぁ面倒ですね ;-)

gitの操作対象は、 つねに「リポジトリ(.git/というコントローラを擁するディレクトリ(階層))」(のみ) というところがポイントだと思います

実行例

SRC-REPOが対象(一部を切り出ししたいリポジトリ)で、 DST-REPOが(切り出したものを)取り込みたい側のリポジトリです。 SRC-REPO以下にある切り出したいサブディレクトリを __subdir__(つまりSRC-REPO/__subdir__)と仮定しています。

$ git clone SRC-REPO
$ git clone DST-REPO
$ cd SRC-REPO
$ git filter-repo --path __subdir__
$ cd ../DST-REPO
$ git remote add TARGET ../DST-REPO
$ git fetch TARGET
$ git read-tree --prefix=tmp/ TARGET/main
$ git remote remove TARGET
  ... 調整作業 ...
$ git commit
$ git push
  • 「… 調整作業 …」の部分
    • tmp/subdir/ が作成されているはずです
    • 適切な場所にgit mvなりしていってください

作業手順 Aパート【輸入元の操作】

  1. まず、操作する対象(輸入元)のリポジトリをチェックアウトします
    • 新鮮(fresh)な作業リポジトリ(SRC-REPO)を作成し、それを操作します
      • 注:そもそも新鮮(fresh)なリポジトリでないとgit filter-repoが動作しません。 これはfail-safeな仕様ですね
    • 対象のデータベースを縮小する操作なので、決して、大元をいじってはいけません
    • 当然、操作後の(この)作業リポジトリ(SRC-REPO)は捨てる前提です
  2. 対象(輸入元)のリポジトリ(SRC-REPO)から(importしたい)部分を切り出します
    • git filter-repo というコマンドを使います
    • git filter-repo というコマンドが(1.22以降)では使えます。 これは、いわゆる grep にあたる操作をするものです (フィルタという表現ですが、これだけでは、どっち向きのフィルタなのか分かりにくい;-)
    • デフォルトではgit filter-repoは使えません。別途インストールが必要です
    [インストール例]
    
    $ sudo apt install git-filter-repo
    
    • 引数に「切り出したいサブディレクトリ」を指定して、切り出す操作を実行します
    [操作例]
    
    $ git clone github/hogeUser/SRC-REPO
    $ cd SRC-REPO
    $ git filter-repo --path __subdir__
    

作業手順 Bパート 【輸入先での操作】

importしたいgitリポジトリ側(DST-REPO)での作業です

  1. 追跡したいリポジトリに名前(ここでは TARGET)をつけてください。 ここで追跡する対象はSRC-REPO (すでに欲しい部分だけが切り抜き済みのリポジトリ)になります
    • このマシン上にある(上で作業した)ディレクトリを指定してください
    • githubにpushしてはいけません
    $ cd DST-REPO
    $ git remote add TARGET 上で切り出し作業をしたディレクトリ(/どこか/SRC-REPO)
    `'`
    
  2. TARGETの内容をfetchします。この結果、TARGETブランチが作成されます
    • .git/ 以下にSRC-REPOからのデータが追加され、ブランチが作成されます
    • 注:データベースに輸入されるだけでファイルは作成されません
    • 注:このあとファイルを展開する作業が続きます
    $ git fetch TARGET
    $ git branch -a
    * main
      remotes/TARGET/main
      remotes/origin/HEAD -> origin/main
      remotes/origin/main
    
  3. TARGETブランチの内容をgit indexに読みこみます(いわゆるgit addした状態にします)
    • 一式あらたにimportすればよい場合は git read-tree コマンドでimportできます
    • indexに取りこんだあと、(git checkoutで)ファイルを展開します
    $ git read-tree --prefix=target-dir/ TARGET/main
    $ git checkout -- .
    
    • ここでtarget-dir/の右端の/(ディレクトリの意味)は大事みたい。忘れないこと
    • ちなみに、新規の場合にgit merge -s subtree ..を実行すると、 fatal: refusing to merge unrelated historiesと怒られます
    • 同じ名前のディレクトリがあってマージが必要な場合はgit mergeです。 マージの難易度によってはmerge strategyの選択が必要になるようです
    [例] (これは未実施のため、雰囲気のみ)
    
    $ git merge -s subtree -X subtree=target-dir TRACK/main
    
  4. git status -s してみるとimportしたファイル群が表示されるはず
  5. git remote remove TARGET
    • importするためだけに必要だったので、追跡対象は削除してOKです
  6. 適切な場所にファイルやディレクトリを移動(git mv …)するなりしてください
  7. git commit
  8. git push