Git サブツリー: Git サブモジュールの代替
Nicola Paolucci
開発者アドボケート
インターネットには、Git サブモジュールを使うべきではないという記事があふれています。若干の使用例でサブモジュールが役立つ場合があるものの、欠点はいくつもあります。
代替手段はあるでしょうか? もちろんあります。少なくとも 2 つのツールでは、Git を使い続けながら、プロジェクト内のソフトウェアの依存関係の履歴を追跡できます。
Git subtree
- google repo
この記事では、git subtree
に注目し、完全とまでは言えないもののそれが git submodule の問題を解決するものであることを説明してみます。
git subtree とは何ですか?なぜそれを使う必要があるのですか?
git subtree
では、あるリポジトリをサブディレクトリとして別のリポジトリにネストできます。これは Git プロジェクトでプロジェクトの依存関係を管理するいくつかの方法のうちの 1 つです。
git subtree
を検討する理由
- シンプルなワークフローは管理が簡単です。
- 古い (v1.5.2 より前の) バージョンの Git がサポートされています。
- 親プロジェクトのクローンが完了した直後からサブプロジェクトのコードが利用可能です。
git subtree
では、リポジトリのユーザーが新たに学ばなければならないことはありません。git subtree
を使用していることを関知せず、依存関係を管理することができます。git subtree
は git submodule のように新しいメタデータ ファイル (.gitmodule) を追加しません。- 依存関係にあるモジュールの内容を変更する場合でも、そのリポジトリのコピーを別に持つ必要がない。
欠点 (ただし、その大部分は許容可能と考えられます):
- 利用者には、新たなマージ戦略 (つまり
.git subtree
) に関する知識が必要です。 - サブプロジェクトの upstream にコードを戻す手順はやや複雑になります。
- 親プロジェクト コードとサブプロジェクト コードをコミットに混在させない責任は各自が負います。
関連資料
Git リポジトリ全体を移動する方法
ソリューションを見る
Bitbucket Cloud での Git の使用方法についてのチュートリアルです。
git subtree の使用方法
git subtree
は 2012 年 5 月以降にリリースされた (Git の v1.7.11 以降) で利用可能です。OSX 上で homebrew を使用してインストールしたバージョンにはサブツリーも適切に組み込まれていますが、プラットフォームによってはインストール手順の実行が必要です。
典型的な使用例として、git subtree
を利用して vim プラグインのトラッキングを行う場合を説明しましょう。
リモート追跡を使用しない迅速かつ不正な方法
数行のみカット アンド ペーストしたいだけであれば、この段落をお読みください。最初に、指定したプレフィックス フォルダーに git subtree
を追加します。
git subtree add --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash
(通常、サブプロジェクトの履歴のすべてを親リポジトリに保存することはありませんが、保存したい場合は --squash フラグを削除すればよいでしょう)。
上記のコマンドで次の出力が生成されます。
git fetch https://bitbucket.org/vim-plugins-mirror/vim-surround.git main
warning: no common commits
remote: Counting objects: 338, done.
remote: Compressing objects: 100% (145/145), done.
remote: Total 338 (delta 101), reused 323 (delta 89)
Receiving objects: 100% (338/338), 71.46 KiB, done.
Resolving deltas: 100% (101/101), done.
From https://bitbucket.org/vim-plugins-mirror/vim-surround.git
* branch main -} FETCH_HEAD
Added dir '.vim/bundle/tpope-vim-surround'
ご覧のとおり、ここでは vim-surround リポジトリの全履歴を 1 つにスカッシュした merge commit を記録しています。
1bda0bd [3 minutes ago] (HEAD, stree) Merge commit 'ca1f4da9f0b93346bba9a430c889a95f75dc0a83' as '.vim/bundle/tpope-vim-surround' [Nicola Paolucci]
ca1f4da [3 minutes ago] Squashed '.vim/bundle/tpope-vim-surround/' content from commit 02199ea [Nicola Paolucci]
後から upstream リポジトリからプラグインのコードをアップデートする場合は、単に git subtree
pull を実行すればよいだけです。
git subtree pull --prefix .vim/bundle/tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git main --squash
この方法は簡便ですが、ややコマンドが長く覚えにくいのが欠点です。サブプロジェクトをリモートとして作成することにより、コマンドを短くすることができます。
サブプロジェクトをリモートとして追加する
サブツリーをリモートとして追加すると、さらに短い形式で参照できるようになります。
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git
これで (以前と同様に) サブツリーを追加できますが、短い形式でリモートを参照できるようになりました。
git subtree add --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash
サブプロジェクトを後の日付でアップデートするコマンドは次のようになります。
git fetch tpope-vim-surround main
git subtree pull --prefix .vim/bundle/tpope-vim-surround tpope-vim-surround main --squash
アップストリームに戻す
これで、ローカルの作業ディレクトリにあるサブプロジェクトに修正を自由にコミットできます。ローカルの貢献をアップストリーム プロジェクトに戻す場合は、そのプロジェクトをフォークして別のリモートとして作成する必要があります。
git remote add durdn-vim-surround ssh://git@bitbucket.org/durdn/vim-surround.git
ここで、次のように subtree push コマンドを実行することができます。
git subtree push --prefix=.vim/bundle/tpope-vim-surround/ durdn-vim-surround main
git push using: durdn-vim-surround main
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 308 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To ssh://git@bitbucket.org/durdn/vim-surround.git
02199ea..dcacd4b dcacd4b21fe51c9b5824370b3b224c440b3470cb -} main
これが完了すると、パッケージ開発全体のメンテナーに対してプル リクエストを送る準備が整います。
git subtree コマンドを使わずにこの作業を行えますか?
はい、可能です。git subtree
は、サブツリーのマージ戦略とは異なるものです。何らかの理由で git subtree
が利用できない場合であっても、マージ戦略を利用することは可能です。ここではその手順を説明します。
依存関係を単純な git remote
として追加します。
git remote add -f tpope-vim-surround https://bitbucket.org/vim-plugins-mirror/vim-surround.git
依存関係の内容をリポジトリに読み込む前に、この時点までのプラグインのツリー履歴全体を追跡できるように、マージを記録することが重要です。
git merge -s ours --no-commit tpope-vim-surround/main
これにより次のような出力が得られます:
Automatic merge went well; stopped before committing as requested
次に、最新のツリー オブジェクトの内容をプラグイン リポジトリに読み込み、コミット可能な作業ディレクトリに格納します。
git read-tree --prefix=.vim/bundle/tpope-vim-surround/ -u tpope-vim-surround/main
これでコミット可能になります (また、これが読み込んだツリーの履歴を保存するマージ コミットになります)。
git ci -m"[subtree] adding tpope-vim-surround"
[stree 779b094] [subtree] adding tpope-vim-surround
プロジェクトをアップデートする場合は、git subtree
マージ戦略を使用して pull を実行すればよいでしょう。
git pull -s subtree tpope-vim-surround main
優れた代替手段である git subtree
git サブモジュールをしばらく使ってみると、git subtree
によって git サブモジュールのさまざまな問題が解決することがわかります。いつものことですが、Git の機能はどれも活用するにはラーニング カーブに沿った経験が必要なのです。
Twitter で @durdn をフォローして、Git に関する他の情報も入手しましょう。Git リポジトリを管理する適切なツールをお探しの場合は、Atlassian Bitbucket をご覧ください。
アップデート:私はこの記事を公開した後、Git subtree の機能に関する記事も執筆しました。
この記事を共有する
次のトピック
おすすめコンテンツ
次のリソースをブックマークして、DevOps チームのタイプに関する詳細や、アトラシアンの DevOps についての継続的な更新をご覧ください。