pockestrap

Programmer's memo

git: shallow cloneしてすぐunshallowする

Shallow cloneとは

Gitには、shallow cloneという便利な機能があります。Shallow cloneを行うことで、最新のコミット履歴のみを取得する代わりに高速にcloneを行うことができます。

古いコミット履歴を取得しないという特性から、これは長い歴史をもつGitリポジトリに対して特に効果があります。

例: ruby/rubyをcloneする例

$ git clone --depth 1 https://github.com/ruby/ruby

Cloning into 'ruby'...
remote: Enumerating objects: 9894, done.
remote: Counting objects: 100% (9894/9894), done.
remote: Compressing objects: 100% (8679/8679), done.
remote: Total 9894 (delta 954), reused 3988 (delta 802), pack-reused 0
Receiving objects: 100% (9894/9894), 13.64 MiB | 2.48 MiB/s, done.
Resolving deltas: 100% (954/954), done.

$ cd ruby/
$ git log --oneline | wc -l
1

Shallow cloneであったとしてもデフォルトブランチに存在するファイルはcloneされてくるため、履歴を見る必要がない操作は問題なく行うことができます。 たとえばgit grepや、git commit, git pushなどが行なえます。またファイルの編集も行えます。 ですが、当然ながらgit loggit blameなどのコマンドは、手元にcloneしてあるコミットに対してのみ有効です。

そのため、たとえば「ライブラリのコードを手元で追いたいためにshallow cloneした」といったケースでは、git grepなどでコードを追っているうちは問題がありませんが、過去の履歴までさかのぼってコードを追いたくなった場合に行き詰まってしまいます。

Unshallow

そこでunshallowという機能が役に立ちます。 Shallow cloneしたリポジトリ内でgit fetch --unshallowを実行すると、そのリポジトリにフェッチされていない全ての履歴をフェッチすることができます。 つまりshallow cloneしたリポジトリであっても、git fetch --unshallowを実行することで過去の履歴も追うことが可能となります。

問題点

当然のことながら、git fetch --unshallowコマンドはgit clone時に高速化した分の時間がかかります。 そのため「過去の履歴も調査したい!」と思ってから実際に調査するまでには、若干の時間がかかってしまうことになります。不便ですね。

解決策

Shallow cloneによって高速にリポジトリをcloneしたい、でも過去の履歴を追う時に待ちたくはない。 この要望を叶えるには、shallow cloneをした直後にバックグラウンドでgit fetch --unshallowを実行すると解決できそうですね。 これによってデフォルトブランチの先頭にあるファイルは高速にcloneしつつ、非同期的に全ての履歴を取得できます。

今回はこの機能をgetというツールに実装しました。 このツールはghq getgo getのラッパーコマンドです。 とりあえずはghq getの代わりにget ghqと打つと動く、と考えておくと良いでしょう。 getについてより詳しく知りたい方は、READMEやリリース時のブログをご覧ください。

github.com

pocke.hatenablog.com

Install

まずはgetをインストールします。

$ go get github.com/pocke/get

Usage

getには-shallow-unshallowの2つのオプションがあります。 -shallowオプションをつけると、リポジトリをshallow cloneします。 そして-unshallowオプションをつけると、shallow cloneが終わった直後にそのリポジトリgit fetch --unshallowを実行します。

例を見てみましょう。

# リポジトリがshallow cloneされた後、バックグラウンドでgit fetch --unshallowが実行される。
$ get ghq -shallow -unshallow https://github.com/ruby/ruby

便利ですね。ですが、少しタイプ数が多いです。 Shallow cloneしてunshallowする挙動は便利なので、これをデフォルトにしてしまうと便利そうです。 そのために設定ファイルを書きましょう。以下の内容を~/.config/get/argsとして保存します。1

-shallow -unshallow

すると、なにもオプションをつけなくてもshallow cloneとunshallowが行われるようになります。

# 特に何も引数を渡さなくても、shallow cloneしてunshallowする
$ get ghq https://github.com/ruby/ruby

便利ですね。

まとめ

Gitのshallow cloneとunshallowの紹介、そしてそれを便利に使う実装であるpocke/getを紹介しました。 この記事を機にpocke/getを使っていただけると嬉しいです。

github.com


  1. この設定ファイルは単純で、単にファイルに書いてある内容をコマンドライン引数として扱います。