Golang とは
ってしっかりと説明する必要が無い気がするので簡単に、
- コンパイル型のプログラミング言語
- オブジェクト指向
- 並列処理得意だよ
いろいろなところに採用されているので golang? しらん
って人も恩恵は受けているかも。
Git サブコマンド とは
Shell のパスが通ったところに、git-hoge
のようなファイルを置いていると
git hoge
のように実行できるようになるものです。
多くの方が知っているかと思いますがそれを今回 go で作ってしまおうというものです。
ちなみに、
Shell のものはGithub - tj/git-extras にまとめられています。
結局何するの??
Git の開発フローは、GitFlow や GithubFlow, GitlabFlow などありますが、
会社やプロダクトによって異なりますよね。
GitFlow では少しかゆいところに手が届かないので
ならば作ってしまおうと言う魂胆です
セットアップ
今回使用するものを自分のマシンに落としてきましょう
やり方は README しっかりに書かれてますね (当たり前
$ go get -d github.com/tcnksm/gcli
$ go get -d github.com/codegangsta/cli
$ go get -d github.com/tcnksm/gcli
$ cd $GOPATH/src/github.com/tcnksm/gcli
$ make install
====> Install depedencies...
go get -v github.com/jteeuwen/go-bindata/...
go get -v -d -t ./...
====> Install gcli in /Users/yuta/.go/bin ...
プロジェクト生成
セットアップが正常に完了したら、ベースとなるものを生成しましょう。
-c
には、コマンドオプションを書いてください。
$ gcli new -c init,feature,hotfix,release,tag git-cirkit
====> WARNING: You are not in the directory gcli expects.
The codes will be generated be in $GOPATH/src/github.com/Yuta Mizui.
Not in the current directory. This is because the output
codes use import path based on that path.
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/README.md
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/CHANGELOG.md
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/feature.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/feature_test.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/main.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/.gitignore
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/release.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/release_test.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/hotfix.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/commands.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/init.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/version.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/init_test.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/tag.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/hotfix_test.go
Created /Users/yuta/.go/src/github.com/Yuta Mizui/git-cirkit/command/tag_test.go
====> Successfully generated git-cirkit
Command owner (author) name. This value is also used for import path name. By default, owner name is extracted from ~/.gitconfig variable.
-o
または-owner
を付け忘れてしまったので、上記のように生成されますね
気を取り直してもう一度
$ gcli new -c init,feature,hotfix,release,tag -o mziyut git-cirkit
====> WARNING: You are not in the directory gcli expects.
The codes will be generated be in $GOPATH/src/github.com/mziyut.
Not in the current directory. This is because the output
codes use import path based on that path.
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/README.md
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/CHANGELOG.md
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/feature.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/feature_test.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/main.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/.gitignore
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/release.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/release_test.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/hotfix.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/commands.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/init.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/version.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/init_test.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/tag.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/hotfix_test.go
Created /Users/yuta/.go/src/github.com/mziyut/git-cirkit/command/tag_test.go
====> Successfully generated git-cirkit
生成されたようなので、とりあえず Build してみましょう。
$ go build github.com/mziyut/git-cirkit
$ ./git-cirkit
NAME:
git-cirkit -
USAGE:
./git-cirkit [global options] command [command options] [arguments...]
VERSION:
0.1.0
AUTHOR(S):
Yuta Mizui
COMMANDS:
init
feature
hotfix
release
tag
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
実際に書いてみよう
今回、開発フローが、git flow
だったと仮定して作成しているので、
git init
の動作を書いてみることにしましょう。
※ 本当は、.git/config
に設定を書き込むのですが、今回は割愛させてください。
生成されたファイルはこのようになってます。
package command
import "github.com/codegangsta/cli"
func CmdInit(c *cli.Context) {
// Write your code here
}
発行したいコマンドは、git checkout -b develop
だとしましょう。
go からコマンドを実行するには、"os/exec"
package が必要なので import に書き足そうと思います。
ついでに、コマンドラインに出力出力するために、"fmt"
も追加しましょう。
package command
import (
"fmt"
"github.com/codegangsta/cli"
"os/exec"
)
func CmdInit(c *cli.Context) {
// Write your code here
}
あ、ちなみに、import 部分は、このようにも書けます。
書き方はお任せします。
import "fmt"
import "github.com/codegangsta/cli"
import "os/exec"
実際に、git checkout -b develop
を動作させるためにはこのように書きます。
exec.Command("git", "checkout", "-b", "develop").CombinedOutput()
最終的に以下のようになります。
package command
import (
"fmt"
"github.com/codegangsta/cli"
"os/exec"
)
func CmdInit(c *cli.Context) {
out, _ := exec.Command("git", "checkout", "-b", "develop").CombinedOutput()
fmt.Println(string(out))
}
out, _
の _
には error が返ってきますが、今回はエラー処理しないので _
にしています。
ではここまで書いたら、Build してみましょう。
$ go build github.com/mziyut/git-cirkit
$ git branch
* master
$ ./git-cirkit init
Switched to a new branch 'develop'
予想していた通りの動作ができたと重います。
では、次に、feature
を作ってみましよう。
inint を作成した時と同じように、import に
"fmt"
, "os/exec"
を追加します。
init
のときと異なるのは、コマンドライン引数を取得するために、
"os"
を追加している点です。
package command
import (
"fmt"
"github.com/codegangsta/cli"
"os"
"os/exec"
)
func CmdFeature(c *cli.Context) {
// Write your code here
}
feature
では branch 番号(feature/◯◯◯
)を取得し、branch 名にするために、
文字の連結を行うのですが、以下のように go の文字連結は遅いので有名です。
文字列を構築する必要がある場合、[]byte 型の値を作ってそれに文字列を追加していって、最後に値を文字列に変換するのがよい。
以上の投稿にある通り書かれているのでそのように実装していこうと思います。
command := os.Args[2]
branch := make([]byte, 0, 15)
branch = append(branch, "feature/"...)
branch = append(branch, os.Args[3]...)
最終的に以下のようになります。
package command
import (
"fmt"
"github.com/codegangsta/cli"
"os"
"os/exec"
)
func CmdFeature(c *cli.Context) {
command := os.Args[2]
branch := make([]byte, 0, 15)
branch = append(branch, "feature/"...)
branch = append(branch, os.Args[3]...)
exec.Command("git", "checkout", "develop").CombinedOutput()
switch command {
case "start":
out, _ := exec.Command("git", "checkout", "-b", string(branch)).CombinedOutput()
fmt.Println(string(out))
case "end":
out, _ := exec.Command("git", "marge", string(branch)).CombinedOutput()
fmt.Println(string(out))
}
}
では(いろいろ不十分かと思いますが)、Build してみましょう。
$ go build github.com/mziyut/git-cirkit
$ git branch
* master
$ ./git-cirkit feature start 1234
Switched to a new branch 'feature/1234'
とりあえずここまで書けたので、
実際に git cirkit
で動作するようにしてみましょう
go install
サブタイトルの通り、コマンドを実行するだけで、
$GOPATH/bin
に作成したものを配置してくれます。
それではやってみましょう。
$ git cirkit
git: 'cirkit' is not a git command. See 'git --help'.
実行前はありませんが・・・・
$ go install
$ git cirkit
NAME:
git-cirkit -
USAGE:
git-cirkit [global options] command [command options] [arguments...]
VERSION:
0.1.0
AUTHOR(S):
Yuta Mizui
COMMANDS:
init
feature
hotfix
release
tag
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
さいごに
ここまで簡単に、Linux,Mac,Windows 環境で動作するコマンドラインツールを作成できました。
簡単なツールであればすぐ作成できると思うので、
ぜひ 1 度やってみてはいかがでしょうか??
今回使用させて頂いたもの