LoginSignup
13
12

More than 5 years have passed since last update.

Gitの内部構造を利用して、特定のディレクトリだけcloneする方法

Last updated at Posted at 2015-05-02

ディレクトリ単位でgit clone/fetchする方法を探していました。sparsecheckoutを利用するという方法も紹介されいましたが、その方法の場合、「最初に普通にcloneする必要がある」というところが、いま探している用途には向いていなかったので別の方法を探してみました。

Gitの内側

まずは、Gitの仕組みを調べるところから始めました。Gitの内側を読むと、Gitの中でどのように変更履歴やディレクトリ構造が保存されているのかがよくわかりました。

  • 変更履歴・ディレクトリ構造を、commit object, tree object, blob objectのグラフで表現している。
  • tree objectには、ディレクトリ中にある、ディレクトリ名やファイル名が保存される。
  • blob objectには、ファイルのコンテンツが保存される。

git構造
git構造

  • cloneするときは、指定したbranchやclone元レポジトリのHEADに紐づく、objectを取得することになる。
  • shallow cloneするときは、branch名等で指定されたcommitの親は辿らずに、参照できるコミットを取得するのだろう。

shallow cloneしたとき図(赤黄緑だけcloneする)
shallow cloneしたとき図

ディレクトリ単位でcloneする方法

Gitの内側を調べてみると、cloneする対象は、指定されたcommit objectとから辿ることが出来る範囲にしぼられることが分かります。ということは、cloneしたいディレクトリ以下のみを辿るcommit objectを作っちゃえば、ディレクトリ単位でgit cloneできるんじゃないかと考えました。

ディレクトリ単位でgit cloneする時の図
ディレクトリ単位でgit cloneする時の図

具体的には、clone元のレポジトリで、cloneしたいディレクトリのtree objectのsha1を調べて、そのobjectを指すcommit objectを作り、さらに、そのcommitを指すブランチやタグを作ります。そしてcloneする際は、作成したブランチを指定してcloneしてやります。

以下、bashでこの操作をやったときの例。

# clone元レポジトリで事前にやっておくこと。
declare BASE_HASH="692c6c9"
declare TARGET_DIR="directory_name"

TREE_HASH=$(git rev-parse $BASE_HASH:$TARGET_DIR)
COMMIT_HASH=$(git commit-tree $TREE_HASH -m 'clone')
git tag -a clone_tag -m 'clone_tag' $COMMIT_HASH

# cloneするときの操作
git clone -b clone_tag (clone元レポジトリのurl)

ここでは、cloneで書きましたが、作成したtagやブランチを指定して、fetch/checkoutすることも出来ます。ただ、任意のディレクトリをclone出来るというやり方ではないので、チーム内で運用ルールを決めるなり、何かのツールの形にまとめるなりといった工夫は必要になりそうです。例えば。

  • コミットする際、上記の操作を自動で行い、pushするときclone_tagも一緒にpushするスクリプトを準備するとか.
  • clone元レポジトリにhookを仕込んで、pushされたら、上記操作を行うとか。

最後に、その他の懸念点を。

  • 親が居ないcommitだと、90日後にgit gcの対象になって消されてしまうかもしれない。確認してないです。
  • 自分の場合、データを取得することのみが必要だったのでこの方法で大丈夫でしたが、 「ディレクトリ単位で取得し、変更コミット、元のブランチにマージ」と言った用途の場合、もうひと工夫必要になりそう。
13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12