こんにちは、しゃかまるです。
Advent Calendarも16日目です。進捗どうですか?私はダメです。
今回もゆるふわな記事です。
概要
シェル芸ってご存知ですか?
こんな感じのことをされている方々です。
私もCUIが好きでgitの操作は全てターミナルでやったりしてるタイプですが、シェル芸人の方々はレベルが違うなぁと感じます。
ここまで自由に文字列操作できたら楽しそうだな、と思ったので、シェル芸人さんたちを目指してGitのマージ済みブランチを検出するコマンドを書いてみました。
テーマが前と一緒じゃ…?
前回はこんな記事(Gitのマージ済みブランチ検出ツールを作った)をGoで書きました。
コンパイルしてバイナリくれ!とか言われるかと思っていたのですが、何の反響もありませんでした。
きっと、Goで書いたのでとっつきづらかったのでしょう。
ということで、前回
この程度だとシェルのワンライナーで書けるんじゃないかな、と思っています
と書いたように、シェルのワンライナーで書いてみました。
これでコピペで動かせるよ!
コマンド
最終的なコマンドは以下になります。
1 |
git branch -a --merged|awk '$0~/^[^\*]/ {print $1}'| while read branch; do echo $branch; git show --summary --pretty=format:'%aN (%aE)%n' $branch |head -n 2; done |
思っていた以上に簡単にできてしまった。。。
なお
1 |
awk '$0~/^[^\*]/ {print $1}' |
としていますが、無駄ですね。
1 |
grep -v '^*' | tr -d ' ' |
で同じことができるし、こっちの方が早いです。
わざわざawkにしたのはそれっぽいし使いたかったという頭の弱い理由です(・ω<)
コマンド解説
ちょっと分解して解説したいと思います。
1 |
git branch -a --merged |
これの解説はいらないですね。
こんな出力結果が得られます。
* develop
remotes/origin/hogehoge
remotes/origin/feature/fugafuga
remotes/origin/feature/piyopiyo
remotes/origin/feature/foobar
以下の方針でやろうと思います。
- カレントブランチは無視
- 左スペースをトリミングする (やらなくても良さそう)
- 出力される各行に対して、git-show コマンドを発行する
カレントブランチを無視
カレントブランチは [*]で始まります。
そのため1文字目が [*] で始まる行を除外します。
1 |
awk '$0~/^[^\*]/ {print $1}' |
もしくは
1 |
grep -v '^*' |
です。
awkの詳しい文法は省きますが
1 |
awk '<PATTERN> <COMMAND>' |
のような形式で実行すると
入力の各行について
awkって何?
横道にそれますが
awkは入力の各行に対して、特定文字で区切って取得した値に対してもろもろの操作を行うことができます。
デフォルトだと連続したwhite spaceで区切ってくれます。
個人的には、データベースの特定のテーブルに対して、カラム名のみを抜き出したい時によく使います。
例えばこんな感じの内容で、hogeというファイルを作成します。
user_id
bigint(20) unsigned NOT NULL,
username
varchar(255) COLLATE utf8_unicode_ci NOT NULL,
profile_image
varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT ”,
以下のコマンドを発行すると
1 |
cat hoge |awk '{print $1}' |tr -d ` |
以下のリストが抜けます。便利ですね。
バッククォートが邪魔なのでtrで消してます。
user_id
username
profile_image
左スペースのトリミング
前述のとおり、awkはデフォルトでwhite spaceの連続を区切りにしてくれるので勝手にやってくれます。
grepを使った場合は余計なスペースが残りますので
1 |
tr -d ' ' |
で消しましょう。
ブランチ名に空白は入らないのでこれで十分ですね。
ここまでで
remotes/origin/hogehoge
remotes/origin/feature/fugafuga
remotes/origin/feature/piyopiyo
remotes/origin/feature/foobar
という結果が得られます。
出力される各行に対して、git-show コマンドを発行する
ブランチ名が綺麗に抜けたので目的のコマンドを発行します。
awkで完結できないかと思っていたのですが、結局whileで回すことにしました。
発行してるコマンドを整形すると以下のようになります。
1 2 3 4 5 |
while read branch do echo $branch git show --summary --pretty=format:'%aN (%aE)%n' $branch | head -n 2 done |
whileで1行ごとに処理します。
1行ずつ read されて 変数i として格納されます。
ブランチ名を表示するため echo $i を発行し、
git-show コマンドを発行してブランチ最終コミッターの名前とアドレスを抜きます。
前回のソースにも書きましたが、 –summary オプションを使うと create modeなどの余計な情報もついてくるので
headに渡していらない情報は除外しています。
こんな感じで目的を達成できました。
$ git branch -a –merged|awk ‘$0~/^[^\*]/ {print $1}’| while read branch; do echo $branch; git show –summary –pretty=format:’%aN (%aE)%n’ $branch |head -n 2; done
remotes/origin/hogehoge
foo (foo@example.com)remotes/origin/feature/fugafuga
bar (bar@example.com)remotes/origin/feature/piyopiyo
bar (bar@example.com)remotes/origin/feature/foobar
fuga (fuga@example.com)
awkの文法の理解がいまいちだったのですが理解が進みました。
CUIを触る人なら覚えておいて損は無いと思います。
なお、タイトルには その1 と銘打ってますが、その2が来るかは分かりません。
明日は石川さんの番です。
参考サイト
http://antibayesian.hateblo.jp/entry/2014/09/15/162605
http://gauc.no-ip.org/awk-users-jp/blis.cgi/awk_fastest
フロントエンドだったりバックエンドだったりサーバだったり その時の流行りと気分でいろいろ迷走してます。