BacklogのGitを快適に使用するコマンドラインツール「gitb」(ギットビー)のご紹介

BacklogのGitを快適に使用するコマンドラインツール「gitb」(ギットビー)をご紹介します。

要約

  • gitbコマンドは、Backlogが提供するGitに関連する操作を補助するツールです。
  • 例えば、現在のリポジトリやブランチに紐付く課題やプルリクエスト等のBacklogが提供する画面を、1コマンドでブラウザから開けます。
  • 全てのgitコマンドをgitbコマンド経由で実行できるので、コマンドを入力する際に両方を意識せずに操作できます。
  • さらに、エイリアスを設定すると、git prgit issue のように、あたかもgitコマンド自身のサブコマンドの如く使用できます。

提供する機能

gitbコマンドで具体的にどのようなことができるのか、提供する機能について一部抜粋して解説します。

リポジトリに紐付く情報を1コマンドでブラウザから開ける

例えば、現在のブランチに紐付くプルリクエストや課題、現在のリポジトリのブランチ一覧、タグ一覧、そしてコミットログ等のBacklogのページを1コマンドで開けます。

全てのgitコマンドをgitbコマンド経由で実行できる

また、gitbコマンドはすべてのgitコマンドをラップしているので、gitbコマンドを経由でgitコマンドが持つサブコマンドを  gitb pull、 gitb push のように実行できます。これで、コマンドを入力する際にgitかgitbなのか意識せずに操作できます。

開発の動機

弊社では、プロジェクト管理やソースコードのバージョン管理に、ドッグフーディングも兼ねてBacklogを使用しています。私は開発者なので、開発する製品のリポジトリに紐つく課題やプルリクエストを1日に何度も作成、閲覧、そして更新します。その度にブラウザからBacklogのダッシュボードを開いて、課題やプルリクエストの作成画面に移動するのですが、このちょっとしたルーチン作業に疲弊していました。

怠慢であり続けるためにも、このようなルーチン作業は自動化する必要があります。

自動化の方針

ルーチン作業のどの辺りに疲弊していたのか、さらにどのような方針で自動化を目指したのか、掘り下げて解説します。

面倒くさいのはブラウザから開きたい画面へ到達するまで

次のフローは。問題のルーチン作業の一例です。開発を始める際の課題作成について書き出しました。

  1. ブラウザを開く。
  2. ブラウザのブックマークバーからBacklogのダッシュボードを開く。
  3. Backlogのダッシュボードから対象のプロジェクトを選択して、課題作成画面を開く。
  4. 課題作成画面から、で課題を作成する。
  5. 課題キーをコピーする。
  6. 端末を開く。
  7. 作業するリポジトリへ移動する。
  8. git checkout -b $NAME で課題キーを含むブランチを作成する。

日々面倒くさく感じるのは、1.から3.のブラウザから課題作成の画面を開く所までです。

コマンドラインツールを起点にした自動化を目指す

この作業を自動化するアプローチはいくつかあると思いますが、端末から実行するコマンドラインツールを起点に自動化することを選択しました。端末からの操作は、自身の日々の作業の起点になることが多く、最も手に馴染んでいたことが理由に上げられます。

次のフローは、想定するコマンドラインツールを起点にした自動化後の作業です。前述のgitbがコマンドラインツールの名前です。

  1. 端末を開く。
  2. 作業するリポジトリへ移動する。
  3. gitb issue add でブラウザから対象のプロジェクトの課題作成画面を開く。
  4. 課題作成画面から課題を作成する。
  5. 課題キーをコピーする。
  6. 端末に戻り、gitb checkout -b $NAME で課題キーを含むブランチを作成する。

ブラウザを開いて、ブックマークを押下して、ダッシュボードから対象のプロジェクトを選択して、課題作成画面を開く、といった一連の作業は
gitb issue add の、1コマンドで自動化されます。

また、BacklogのAPIを使用すれば、gitb issue add --title=foo といった形で、課題作成を完了するところまで自動化できるのですが、あえてそこはスコープから外しました。実際に生きた課題を作るために必要な情報はタイトル以外にも複数あります。課題詳細、担当者、マイルストーン、ステータス等、1コマンドでそれらの情報を入力するのは至難の技です。

インストール方法

gitbコマンドをインストールする方法を解説します。

Homebrew

MacOSで使用可能なパッケージマネージャであるHomebrewでインストールできます。

brew tap vvatanabe/gitb
brew install gitb

Go

Go言語(go1.13+)をインストールしていれば、go get でもインストールできます。

go get github.com/vvatanabe/gitb

Github Release Page

ビルド済のバイナリはGitHubのリリースページからOS毎にダウンロードできます。ダウンロード後、パスが通ったディレクトリに配置してください。

基本的な使い方

よく使用するであろう課題の操作を行う gitb issue、プルリクエストの操作を行う gitb pr の使い方、そしてその他の便利な設定について解説します。gitbが提供する全のコマンド、具体的なオプション、そして引数に関しては、以下のドキュメントページを参照してください。

プルリクエスト一覧を開く

gitb pr [-s, --state <STATE>]

現在のリポジトリが持つプルリクエストの一覧ページを開きます。<STATE>の値でプルリクエストをフィルタリングします。

値は、 open(初期値)、closedmerged、 allのいずれかを指定します。

プルリクエストを開く

gitb pr show

現在のブランチに関連したプルリクエストのページを開きます。

gitb pr show [<PR-ID>]

指定した<PR-ID>のプルリクエストのページを開きます。<PR-ID>を指定しない時は、現在のブランチに関連したプルリクエストのページを開きます。

プルリクエストを追加する

gitb pr add [-b, --base <BASE>]

現在のブランチをトピックブランチにしたプルリクエストを追加するページを開きます。

BASEはプルリクエストのベースとなるブランチ名です。デフォルトは空です。

ファイルの行単位で関連するプルリクエストを表示する

gitb pr blame [git blame command options] <PATH>

以下のように、指定した<PATH>の変更に関連するプルリクエストIDを行単位で表示します。git blameコマンドのオプションを適用できます。この機能はkazuho/git-blame-pr.plをポーティングして作成しました。

$ git pr blame -s ./main.go
(省略)
PR #6  55) Subcommands: []cli.Command{
PR #6  56)     {
PR #6  57)         Name: "show",
PR #21 58)         Usage: "Open the pull request page. When no specify <PR-ID>, open the PR page related to the current branch",
PR #6  59)         Action: func(c *cli.Context) error {
PR #13 60)         repo, err := open(".")
(省略)

さらに、表示したプルリクエストのIDを gitb pr show 55 のように渡せば、対象のプルリクエストの画面をすぐに開くことができます。

課題一覧を開く

gitb issue [-s, --state <STATE>]

現在のプロジェクトの課題一覧ページを開きます。<STATE>の値で課題をフィルタリングします。

値はallopenin_progressresolvedclosednot_closed(初期値)のいずれかを指定します。

課題を開く

gitb issue show

現在のブランチに関連する課題ページを開きます。

課題を追加する

gitb issue add

現在のプロジェクトに課題を追加するページを開きます。

エイリアスの設定

gitbコマンドをgitコマンドとして使う場合は、.xxxrc(.bashrc、.zshrc、config.fish)に次のエイリアスを記述してください。

Bash, Zsh:

function git(){
  gitb "$@"
}

Fish:

function git
  gitb $argv
end

これで、コマンドを入力する際にgitかgitbなのか意識せずに、gitbが提供するサブコマンドであるprやissueが、あたかもgitコマンド自身のサブコマンドのように使用できます。

動作の仕組み

gitbはどのような仕組みで動作しているのか、一部の機能をかいつまんで解説します。

gitb自体はGolangで実装されています。言語選定の理由としては、各OSで実行するためのバイナリを簡単にクロスコンパイルできること、自分が使い慣れていることの2つです。

内部的にはgitコマンドを実行して必要な情報を収集しており、一部GitのGolang実装であるgo-gitを使用しています。

関連するプルリクエストの画面を開く道のり

現在のブランチからどのようにプルリクエストの画面を探索しているのか解説します。

1. 現在のブランチの名前を取得する:

現在のブランチの名前は.git/HEADref: refs/heads/$BRANCH_NAMEの形式で保持されているため、このファイルをパースして取得しています。ここでは仮にブランチの名前をpatch-3とします。

2. リモートの参照のリストを取得する:

git ls-remote コマンドでリモートの参照(ブランチやタグ等)のリストを取得します。次のように、参照のリストには各ブランチやタグの先頭のコミットIDが紐ついています。

f6d550773a1cddb09bdab1c94f5c197abca9750c	HEAD
f6d550773a1cddb09bdab1c94f5c197abca9750c	refs/heads/master
22ee6e85764d4788a9cb5ce8762365d77b2e7688	refs/heads/patch-1
61242c8bcea3d82321b7eaa56b5c0b484118ddcb	refs/heads/patch-3
22ee6e85764d4788a9cb5ce8762365d77b2e7688	refs/pull/2/head
61242c8bcea3d82321b7eaa56b5c0b484118ddcb	refs/pull/4/head
2674ad54e116b4a05d933aa75c7af0657afd0079	refs/tags/0.1.0
cf1cbb47a771e136377cb24e95861485a18bcffa	refs/tags/0.2.0

3. 現在のブランチの先頭のコミットIDを取得する:

参照のリストから、現在のブランチであるpatch-3のコミットIDを取得します。ここでは61242c8bcea3d82321b7eaa56b5c0b484118ddcbが対象となります。

4. 3.と同じコミットIDを先頭に持つプルリクエストの参照を取得する:

現在のブランチの先頭のコミットIDである、61242c8bcea3d82321b7eaa56b5c0b484118ddcbを先頭に持つプルリクエスト用の参照を取得します。ここではrefs/pull/4/headが対象となります。

5. プルリクエストIDを取得する:

プルリクエスト用の参照であるrefs/pull/4/headの数字の部分がプルリクエストのIDとなります。ここでは4がプルリクエストIDです。

6. リモートリポジトリのURLを取得する:

リモートリポジトリのURLはローカルリポジトリ内の.git/configに次の形式で記述されています。このファイルをパースして取得しています。ここでは、https://foo.backlog.jp/git/BAR/baz.gitがURLとなります。

[remote "origin"]
        url = https://foo.backlog.jp/git/BAR/baz.git
        fetch = +refs/heads/*:refs/remotes/origin/*

7. ホスト、プロジェクトキー、リポジトリ名を取得する:

取得したリモートリポジトリのURL https://foo.backlog.jp/git/BAR/baz.git から、ホストの foo.backlog.jp、プロジェクトキーの BAR、そしてリポジトリ名の baz を取得します。

8. BacklogのプルリクエストのURLを整形する。

ホスト、プロジェクトキー、リポジトリ名、プルリクエストIDを元に、次の形式でプルリクエストのURLを組み立てます。

https://foo.backlog.jp/git/BAR/baz/pullRequests/4

9. プルリクエストURLを開く。

最後に、組み立てたプルリクエストのURLをブラウザで開きます。Golang標準ライブラリの exec.Cmd 構造体に、コマンドとURLを指定して Run() 関数で実行しています。Linuxは xdg-open 、Mac OSXは open 、そして、Windowsは rundll32.exe に url.dll の FileProtocolHandler を指定して実行します。

gitコマンドをgitbコマンド経由で実行する

gitbが提供するコマンドに当てはまらない場合は全て、gitコマンドに対して引数とオプションをそのまま渡すシンプルな実装になっています。

gitコマンドの内部的な実行方法としては、Golang標準ライブラリの syscall.Exec() 関数を使用しており、対象のgitコマンドでgitbのプロセス自体を置き換えています。そのため、gitbとgit間でデータをやりとりするためのコードは一切なく、対象のgitコマンドを直接実行するのとほぼ変わりません。

ただし、Windowsにおいては、syscall.Exec() 関数にサポートされていないので、exec.Cmd 構造体に標準入力、出力、そして、エラー出力を渡して、Run() 関数で子プロセスとして実行するようになっています。

まとめ

以上、コマンドラインツールgitbについて解説しました。ちょっとしたツールですが、少しでも皆様の役に立てれば幸いです。バグ、質問、ディスカッションについてはGitHub Issuesをご利用ください。

謝辞

  • gitbを実装する上でGitHubのコマンドラインツールであるhubがとても参考になりました。
  • git pr blame コマンドはkazuho/git-blame-pr.plをポーティングして作成しました。

ありがとうございました!

タスク管理、ファイル共有もできるプロジェクト管理ツールBacklog

チームで使うプロジェクト管理・タスク管理ツール

カテゴリ一覧