メインコンテンツまでスキップ

ghqでプロジェクト管理(整理)する

· 約6分
mebiusbox
engineer

ある程度、自分なりにクローン先を指定して管理していたのですが、数が多くなって管理が難しくなってきたので、ghq を使ってみました. ここでは、その備忘録を残しておきます.

ghq はリポジトリをクローンするときに、ルールにもとづいて自動的にフォルダを生成して、そこにクローンしてくれるツールです.一貫した構成になるので、管理しやすくなりますし、ghqコマンドを使ってリストを取得することもできます.fzfと組み合わせることで、プロジェクトの行き来が楽になります.

すでにある程度、自分なりにクローン先を分別してやっていたのですが、いざ不要なものを削除するときにわかりづらいものとなっていました. たとえば、GitHubで管理しているものとローカルに作成したベアリポジトリ(バックアップ用)の区別がつきませんでした. そこで、ghqを導入して整理することにしました.100個以上のクローンしたプロジェクトがあったので、なるべく一括でできるようにPowerShellでスクリプトを作成しました. 前述したように GitHubで管理しているものとローカルに作成したものがあったのですが、ghqではローカルに作成したもの(sshhttps以外)は上手くいかなかったので、そこはいい感じの構成にしておきました(repoディレクトリの中に xxx.gitディレクトリが置いてあるので、<ghq.root>/repo/<project> という名前にしました). あとは、すでにあるプロジェクトを移行します.migrate2ghqという関数を作成してghqのフォルダ構成になるように移動するものです.

function migrate2ghq() {
param(
[Parameter(Mandatory)]
[string]$InputPath,
[switch]$DryRun
)
Push-Location
Set-Location $InputPath
Write-Host "Location: $(Get-Location)"
$url = git remote get-url origin
Write-Host "Origin : ${url}"
Pop-Location
$root = git config --global ghq.root
Write-Host "ghq.root: ${root}"
$repo = @{}
if ($url -match "^git@(?<host>.*?):(?<user>.*?)/(?<project>.*?)\.git$") {
$repo = @{
Host = $Matches.host
User = $Matches.user
project = $Matches.project
}
} elseif ($url -match "^https://(?<host>.*?)/(?<user>.*?)/(?<project>.*?)\.git$") {
$repo = @{
Host = $Matches.host
User = $Matches.user
project = $Matches.project
}
} elseif ($url -match "^(?<drive>\w+?):[/\\].*?(?<host>.*)[/\\](?<project>.+)\.git$") {
$repo = @{
Host = $Matches.host
User = ""
project = $Matches.project
}
} else {
Write-Error "Not found repository information. Couldn't migration."
return
}

# <ghq.root>/<host>/<user>/<project>
$outputPath = Join-Path $root $repo.host $repo.user $repo.project
$outputParentPath = Join-Path $root $repo.host $repo.user
if (-not(Test-Path $outputParentPath -Type Container)) {
if ($DryRun) {
Write-Host "MKDIR(DryRun): ${outputParentPath}"
} else {
New-Item -Path $outputParentPath -ItemType Directory
}
} else {
if (Test-Path $outputPath -Type Container) {
Write-Error "[${outputPath}] is Already exists."
return
}
}
if ($DryRun) {
Write-Host "Move(DryRun): ${InputPath} -> ${outputPath}"
} else {
Move-Item -LiteralPath $InputPath -Destination $outputPath
Write-Host "Move: ${InputPath} -> ${outputPath}"
}
}

使い方は次のようになっています:

PS > migrate2ghq hoge -DryRun
PS > migrate2ghq hoge

リポジトリはリモートの origin に紐づいているURLを参照します. また、ghqのルートパスはgitのグローバルに設定されていることを想定しています. 現在のディレクトリに一括で行う場合は次のように使います:

PS > Get-ChildItem -Attributes Directory | { migrate2ghq $_ -DryRun }
PS > Get-ChildItem -Attributes Directory | { migrate2ghq $_ }

これであまり手間をかけずに移行できました. ただ、完全に ghq で管理できるようになったわけではなく、いくつかのプロジェクトはその構成上 ghq に合わないため、除外しています. また、クローン先は他にも2種類あって、高速なSSDと通常のHDDに分けており、その場合はどちらかが ghq 管理外としています. 実際には、ghqを使って取得したリストと別のフォルダで管理しているリストを切り替えて検索できる関数を作成して使用しています. この場合は ghq を使わずとも今回作成した migrate2ghq を調整して、まず適当な場所にクローンしてから migrate2ghq で移動するのもありかなと思います. 残念ながらすべてを ghq 管理下に置くことはできませんが、全然マシかなと思っています.

以上です.