| title | type | published |
|---|---|---|
リポジトリを取得する(`ghq get`) |
tech |
true |
ghq getは引数か標準入力経由でtargetを受け取り、そのリポジトリを取得します。
% ghq get <target> [<target>...]
% cat repolist.txt | ghq get --parallelghqはいい感じにこのtargetを解釈するので、柔軟な指定が可能です。
targetはhttps://{{Host}}/{{Path}}が基本形です。https://は常に省略可能で、ホストがgithub.comの場合、それも省略できます。つまり、以下の3つは同じ意味になります。
% ghq get https://github.com/x-motemen/ghq
% ghq get github.com/x-motemen/ghq
% ghq get x-motemen/ghqもちろんGitHub以外のホストも指定可能です。
% ghq get launchpad.net/terminatorまた、通常のリポジトリURLでのtarget指定も可能です。http scheme以外のURLも受け付けます。
% ghq get git@github.com:x-motemen/ghq.git
% ghq get svn+ssh://svn.example.com/yourprojectghq get --update(-u) オプションを利用すれば、リポジトリが取得済みの場合でも最新の状態への更新をおこなってくれます。
ghqは標準でhttpsでのリポジトリ取得を試みます。しかし、プライベートリポジトリをSSHで取得したい場合や、OSSであってもコードのpushはSSHでおこないたいということもあるでしょう。Gitの細かい設定には立ち入りませんが、この解決のためには以下のような選択肢があります。
url.<base>.insteadOfを設定してSSHを強制するghq getのtargetにSSH URLを利用するghq get -pオプションを使ってSSHでの取得に切り替える- SSHを使わない(git credential等を適切に設定してhttpsでpullとpushをおこなう)
好みの方法を選択すれば良いのですが、-pオプションを使ってSSH取得をするより、Gitの設定を整えて、取得したほうが統一感が出て望ましいでしょう。筆者はソースコードの取得はhttpsでおこない、pushはurl.<base>.pushInsteadOfを設定してSSHでpushするようにしています。
ghq rootの設定には先程触れましたが、仕事用と趣味用のコードで取得ディレクトリやgitの設定を切り替えたいこともあるでしょう。これはghq.<base>.root設定で実現できます。
以下は、標準では~/hobbyに、自社のGitHubオーガニゼーションや自社のVCSホスト配下のリポジトリは~/workに取得する設定例です。
[ghq]
root = ~/hobby
[ghq "https://github.com/mycompany"]
root = ~/work
[ghq "https://myvcs.example.com"]
root = ~/workGitの設定の話になりますが、このとき、includeIf設定を併用すると、特定のgitconfigを特定のディレクトリ配下のリポジトリのみに適用することができます。~/work以下のリポジトリに対して仕事用のgitconfig(~/work/.gitconfig)を適用させる例が以下です。
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig余談ですが、$GHQ_ROOT環境変数が設定されている場合、他のghq.root設定に関わらず、そのディレクトリ配下にリポジトリ取得をおこないます。これは、更に動的に取得ディレクトリを切り替えたい場合に役に立つこともあるでしょう。
GitHubのリポジトリパスは{{Owner}}/{{Project}}の形式を取りますが、ghq get {{Project}}のように、スラッシュを含まないリポジトリ名のみをghq getに与えた場合、ghqはownerの補完を試みます。例えば、私(Songmu)の場合、ghq get horensoとすると、github.com/Songmu/horensoリポジトリを取得します。
この補完は以下の順番でおこなわれます。
ghq.userが設定されている場合それを使う- GitHubユーザー名をローカル環境から推定する
- ログイン名(
$USER環境変数。Windowsの場合$USERNAME環境変数)
2の推定には、github.com/Songmu/gitconfig.GitHubUser関数を用いているので詳細を知りたい場合はそちらを参照してください。
ところで、補完するowner名に自身を使うのではなく、そのリポジトリ名を使いたいこともあるでしょう。例えば、rubyをgithub.com/ruby/rubyに、vimをgithub.com/vim/vimに、pecoをgithub.com/peco/pecoに、といった具合です。
この挙動の方が好みの場合、ghq.completeUser設定をfalseに設定することで、挙動を切り替えられます。
% git config --global ghq.completeUser falseghq getは指定されたtargetに対して、極力適切なVCSを判別しようとしますが、--vcsオプションで明示的に指定することもできます。以下はfossilの例です。
% ghq get --vcs fossil https://www.sqlite.org/srcまた、特定のリポジトリホスト下のVCSを決め打ちできる場合、それを ghq.<base>.vcs で設定できます。以下は、https://svn.example.com 下のリポジトリをSubversionで取得する設定です。
[ghq "https://svn.example.com"]
vcs = svnリポジトリ取得と同時に、そのリポジトリの内容をすぐに見たいと思うのは自然でしょう。そのためのghq get --lookオプションがあります。これはcpanm --lookにインスパイアされた機能ですが、リポジトリ取得後に取得ディレクトリに移動します。
リポジトリが取得済の場合でも、ディレクトリへの移動はおこなわれるため、手元のリポジトリの一時的な確認のためにも便利です。また、ghq get --look --update <target>とすれば、最新の状態に更新しながらソースの確認がおこなえます。
確認が終わったら、exitコマンドで抜けてください。
また、この--lookの利用はあくまでソースの一時的なチラ見のために留め、作業ディレクトリの移動用には利用しないようにしてください。
--lookオプションは子プロセスで別のシェルプロセスを起動して、ディレクトリを移動したように見せかけています。このため、シェルの設定がうまく引き継がれなかったり、戻るときにexitする必要があるといった直感的でない挙動が発生します。また、シェルを起動し直すため、シェルの起動時間がかかってしまうという問題もあります。
ですので、作業ディレクトリの移動には以下のように、素直にcdをするのがおすすめです。
% cd $(ghq list --full-path --exact x-motemen/ghq)このあたりは、次のghq listの章で説明しますが、ディレクトリの移動はpecoやfzfのようなフィルタツールと連携して移動するのが王道パターンなので、それらの設定を整えることをおすすめします。
あまり知られざるghq getのtarget指定方法として、相対パス指定があります。
% ghq get ../projBこれは例えば、 github.com/<your-org>/projA で作業しているときに、同じオーガニゼーション配下の別リポジトリ(この例の場合はprojB)を取得したい場合に利用します。
ghq getにはここまで取り上げていない幾つかのオプションがあります。最後にそれらをまとめて紹介します。
--parallel, -P- 複数のtargetがある場合、並列で取得をおこないます。このオプションが指定された場合、一部のリポジトリの取得に失敗してもそのエラーを表示するのみで、コマンドの中断はされません。このオプションの活用方法は後の章で個別に取り上げます。
--shallow- 最新の履歴のみ取得することで高速にリポジトリを取得します。Git, git-svn, Darcsのみ対応しています
--branch, -b- ブランチを指定して取得します。Git, git-svn, Mercurial, Subversionのみ対応しています。特にGitの場合
git clone --single-branchオプションを利用するため、高速な取得が望めます
- ブランチを指定して取得します。Git, git-svn, Mercurial, Subversionのみ対応しています。特にGitの場合
--no-recursive- Gitの場合、標準ではsubmoduleの取得も自動で再帰的におこないますが、それを抑制するオプションです
--silent, -sghqのコンソール出力を削減します。具体的には外部コマンド出力の表示を抑制します。デフォルトfalseですが、--parallelオプション指定時には出力が混ざらないように強制的にtrueになります