ブランチと手術

サブツリー

サブツリーは、別のリポジトリを自分のディレクトリの中にコピーします。そのあとファイルは 本当にそこにあります。ふつうの git clone で手に入り、git checkout はほかの ファイルと同じように動かし、そのディレクトリがよそから来たことを誰も知らなくて構い ません。

サブモジュール との違いはまさにそこです。サブモジュールはポインタしか 保存せず、--recurse-submodules と、自前のチェックアウトと、把握し続けるべき自前の detached HEAD を必要とします。

⌘K → サブツリー。

履歴から見つかった取り込み済みディレクトリと、Gitcito が覚えているその取得元

誰も言わない落とし穴

git はサブツリーのマニフェストを記録しません。 サブモジュールには .gitmodules があり、url とパスがすべて並んでいます。サブツリーには何もありません。取り込みを行った コミットに付いた git-subtree-dir: トレーラーだけです。

つまりリポジトリはサブツリーを含みながら、それがどこから来たのかを知る手立てを与えて くれない、ということが起こり得ます。Gitcito はできる範囲のことをします。

  • 一覧は、そのトレーラーを読むことで履歴から発見されます。誰がどんなツールで追加した サブツリーでも現れます。
  • 取得元のリポジトリと ref は Gitcito が、このリポジトリの git 設定に覚えて おきます。履歴から発見されたサブツリーは、最初その欄が空です。一度埋めれば、そこ から先はプルもプッシュも動きます。

覚えられた値は .git/config の gitcito.subtree.* にあるので、リポジトリには 残りますがクローンには付いていきません。忘れる はそれを消すだけで、ほかには 何も触れません。

追加する

項目 意味
ディレクトリ 置き場所。例: vendor/parser。まだ存在していてはいけません
取得元リポジトリ URL、またはディスク上のパス
ブランチまたはタグ 取り込む対象
スカッシュ 履歴すべてではなく、1 コミットとして取り込む

理由がない限り スカッシュはオンのままに。オフにすると、そのライブラリのすべての コミットが自分のログに永久に織り込まれ、git log は自分のプロジェクトの話ではなく なります。

付き合っていく

操作 実行されるもの
プル git subtree pull — 上流の変更が、そのディレクトリへのマージとして届きます
プッシュ git subtree push — そのディレクトリ配下のローカルの変更を取得元へ戻します
スプリット git subtree split -b <branch> — そのディレクトリ自身の履歴を、ファイルをルートに置いたブランチとして取り出します

覚えておく価値があるのは スプリット です。取り込んだディレクトリを、単体の リポジトリの履歴へ戻します。サブツリーがサブツリーであることをやめる方法が、これです。

知っておくべき制限

  • プッシュは遅いです。 毎回そのディレクトリの履歴をゼロから計算し直します。大きな リポジトリでは一瞬ではなく数秒から数分かかり、Gitcito にできるのは待つことだけです。
  • プルはマージです。 ほかのマージと同じようにコンフリクトし得るので、 リゾルバ に着地します。
  • git subtree は contrib のスクリプト であり、git の組み込みコマンドではありま せん。切り詰められた git のインストールには入っていないことがあります。Gitcito は 「'subtree' is not a git command」をそのまま渡すのではなく、はっきりそう伝えます。
  • スカッシュした履歴はあとから戻せません。 それらのコミットは、そもそも取り込ま れていないからです。
  • Gitcito はサブモジュールをサブツリーに変換しませんし、その逆もしません。

関連項目: マージとリベース · UI 付きの配管コマンド

この翻訳を GitHub で改善