はじめに
みなさんローカルに溜まっていくgitのブランチをどのように整理していますか?
自分は
$ git branch
foo
bar
baz
$ git branch -D bar baz
$ git branch
foo
のように、 git branch
で一覧を表示した後、不要なものをコピペして削除していました。
prune
や --merged
を使えば、マージされているブランチを
いい感じに 削除できるようですが、
「一覧から好きなものを選んで削除したい!」と思ったので、作ってみました。
簡単にコマンドライン上でのチェックボックスを実装できるライブラリはないかなと探し、
PyInquirer を見つけたので、これを使いました。
完成したもの(gif)
実装
やりたいことの整理
やりたいことは、
- ブランチ一覧の取得
- 一覧からの複数選択
- 選択したブランチの一括削除
です。
1, 3については はじめに
でも書いたように
$ git branch
$ git branch -D foo bar baz
で実現できるます。
これらはPythonスクリプト内で subprocess
を使って実行するようにして、
最終的なスクリプトは以下のようになるイメージで進めます。
if __name__ == '__main__':
output = subprocess.check_output(['git', '-P', 'branch'])
# output から branch_list を抽出する処理
# ...
subprocess.call(['git', 'branch', '-D'] + delete_branch_list)
2について PyInquirer
を使って実装し、
選択したブランチの一覧を git branch -D
に渡すような処理を書いていきます。
PyInquirerの挙動確認
実装する前にまず、PyInquirer
の使い方について簡単に触れます。
quickstartには
you define a list of questions and hand them to prompt
prompt returns a list of answers
と書かれています。
今回は複数選択のためにチェックボックスを使いたいので、
Pyinquireが用意してくれているexample
を少し見ます。
exampleを少し編集して、挙動を確認します。
from pprint import pprint
from PyInquirer import prompt, Separator
questions = [
{
'type': 'checkbox',
'qmark': '😃',
'message': 'Select toppings',
'name': 'toppings',
'choices': [
{'name': 'Ham'},
{'name': 'Ground Meat'},
{'name': 'Bacon'}
]
},
{
'type': 'checkbox',
'qmark': '🧀',
'message': 'Select toppings2',
'name': 'toppings2',
'choices': [
{'name': 'Mozzarella',},
{'name': 'Cheddar'},
{'name': 'Parmesan'},
]
}
]
answers = prompt(questions)
pprint(answers)
実行すると
まずquestionsの一つ目のchoicesが表示されました。
が得られました。
quickstartに書いてある通りですが
prompt
は、引数に渡した questions
を順番に実行し、
各questionの回答を辞書に詰めて返してくれることが分かりました。
(チェックボックスは List で返してくれる)
では PyInquirer
の挙動が確認できたので実装します。
お掃除スクリプト実装
上で試した結果、promptに渡す questionsをこのようにすれば良さそうです。
branch_choices = [
{'name': 'foo'},
{'name': 'bar'},
{'name': 'baz'}
]
questions = [
{
'type': 'checkbox',
'name': 'delete_branch_list',
'message': '削除するブランチを選択',
'choices': branch_choices
}
]
なので、まず branch_choices
を作成する処理を書きます。
# -P オプションをつけることで paginate なしでブランチの一覧を取得できる
output = subprocess.check_output(['git', '-P', 'branch'])
# split('\n')で最後に改行分の空文字が入ってくるので[:-1]とする
branch_choices = [
{'name': branch_name.replace(' ', '').replace('*', '')}
for branch_name in output.decode().split('\n')[:-1]
]
ではこれをchoicesとするquestionsをpromptに渡します。
questions = [
{
'type': 'checkbox',
'name': 'delete_branch_list',
'message': '削除するブランチを選択',
'choices': branch_choices
}
]
answers = prompt(questions)
これでanswersに delete_branch_list
という key で、
選択したブランチのlistを詰めて返してくれるようになりました。
一応、選択なしだった時のif文等を追加して、完成させます。
↓が完成物です。
# -*- coding: utf-8 -*-
import sys
from PyInquirer import prompt, Separator
import subprocess
output = subprocess.check_output(['git', '-P', 'branch'])
# split('\n') で最後に空文字が入ってくるので[:-1]としている
branch_choices = [
{'name': branch_name.replace(' ', '').replace('*', '')}
for branch_name in output.decode().split('\n')[:-1]
]
questions = [
{
'type': 'checkbox',
'name': 'delete_branch_list',
'message': '削除するブランチを選択',
'choices': branch_choices
}
]
answers = prompt(questions)
if not answers:
sys.exit()
delete_branch_list = answers.get('delete_branch_list')
if not delete_branch_list:
print('選択されたブランチはありませんでした。')
sys.exit()
subprocess.call(['git', 'branch', '-D'] + delete_branch_list)
おわり
PyInquirer
非常に便利でした。
ありがとうございました。