複数のGitプロジェクトをcloneしていると、「ブランチが最新じゃなかった!」が原因で、想定外の動作をしていた…という場面がありました。また、マイクロサービスアーキテクチャを採用していた場合、プロジェクト数が多くなる可能性1があり、各プロジェクトの状態確認の時間がとても手間です。
- 動作が担保されているブランチに切り替えられれば良い
- ローカルのブランチを一括で綺麗にしたい
案外簡単にできるかな…と思っていたのですが、少し嵌ったことがあるのでまとめておきたいと思います。
前提
- shell で実行できる
- PowerShell でも同じことができると思います(やりたいコマンドをps用に書き換える必要あり)
- 「#bin/bash」や「現在ディレクトリの変数化」等のお作法は記載しません
結論
checkoutBranch='develop'
projectDirs=(
'Gitプロジェクトまでのディレクトリパス' 'Gitプロジェクトまでのディレクトリパス'
'Gitプロジェクトまでのディレクトリパス' '...'
)
for projectDir in ${projectDirs[@]};do
cd $projectDir
git fetch --prune
git checkout $checkoutBranch
git pull origin $checkoutBranch
featureBranches=$(git for-each-ref --format="%(refname)" | grep "^refs/heads/" | sed -e "s/refs\/heads\///" | grep -v "$checkoutBranch")
if [[ $featureBranches != "" ]]; then
git beanch -D $featureBranches
fi
done
紐解く
大まかな処理の構成は下記となります。
- 「Gitプロジェクトのディレクトリパスを一覧で取得」
- 「1 で取得したGitプロジェクトごとに処理を実行する」
2-1. 「Gitプロジェクトに移動」
2-2. 「ローカルのGitプロジェクトの最新化」
2-3. 「ローカルのブランチの一覧取得」
2-4. 「2-3 で取得したブランチの一覧から、切り替えたいブランチ以外を絞り込む」
2-5. 「2-4 のブランチを削除する」
コメントを含めた形にするとこうなります。
checkoutBranch='develop'
# 1
projectDirs=(
'Gitプロジェクトまでのディレクトリパス' 'Gitプロジェクトまでのディレクトリパス'
'Gitプロジェクトまでのディレクトリパス' '...'
)
# 2
for projectDir in ${projectDirs[@]};do
# 2-1
cd $projectDir
# 2-2
git fetch --prune
git checkout $checkoutBranch
git pull origin $checkoutBranch
# 2-3, 2-4
featureBranches=$(git for-each-ref --format="%(refname)" | grep "^refs/heads/" | sed -e "s/refs\/heads\///" | grep -v "$checkoutBranch")
if [[ $featureBranches != "" ]]; then
# 2-5
git beanch -D $featureBranches
fi
done
嵌った部分
このシェルの重要な部分は、『2-3. 「ローカルのブランチの一覧取得」』です。
そして、その部分に嵌りました…。
「Git のブランチの一覧表示」といえば、 $ git branch
かと思います。
ただ、これだと個人的にはうまくできなかったです。
やりたいことは、「ブランチ名を取得してアレコレしたい…」だったので調べたところ、 for-each-ref を見つけ解決しました。
あとは、取得できた文字列を良い感じに削除用の文字列に変換をしたり絞り込みをして実現しました。
注意点
git branch -D
を利用しています。一度リセットをする目的のために -d
ではなく、 -D
を使っていますので、作業中のブランチがあった場合は削除されてしまいます。
もしも誤って削除してしまった場合は、 git reflog
を実行し復元したい状態を確認し、 git branch ブランチ名 HEAD@{ログ番号}
で元に戻しましょう。
最後に
「結論」として最小限のシェルをまとめました。ただ、このまま利用すると想定外のミス(削除したくないものまで削除してしまった…)や、少しの手間や無駄なログが表示されるといった、微妙な状態となっています。
- 不要な出力を /dev/null に流して、出力を抑える
- 処理中のプロジェクトを表示する
- 削除対象のブランチが何かを表示する
- 削除前に、削除して良いかのチェック処理を入れる
- 削除開始と削除完了後を表示する
- シェルファイルを配備したら、そのファイル直下の全てのディレクトリを対象としてくれるようにする
- ディレクトリを指定したら、そのディレクトリ直下の全てのディレクトリを対象としてくれるようにする
- etc...
実際に使う場合は、こういったことを意識して改造をすると良いと思います。
「こういう風なシェルに改造したら使いやすかったですよ!」というようなアイデアは、コメントに頂けると嬉しいです。
面倒な作業が少しでも減らせられれば幸いです。それでは。
-
「1つのGitプロジェクトに複数サービス入れれば良いのでは?」という提案もあると思います。各サービスのバージョン管理の方針次第ですが、分割しておいた方が柔軟性があるため、案件プロジェクトによって選ぶと良いと思います。 ↩