Goでgitリポジトリを操作しようと軽くトライした話
はじめに
PerlやRubyで色々ツールを作っていた頃
Git::Repository - search.cpan.org
GitHub - schacon/ruby-git: Ruby/Git is a Ruby library that can be used to create, read and manipulate Git repositories by wrapping system calls to the git binary.
この辺りを使って、差分を見てよしなに本番作業の手順書を自動生成したりしたのを思い出して、今でも個人プロジェクトではRubyとかPerlで描いてしまうことが多いのですが、Goでそのあたりを書くためにはどうすればいいか試行錯誤した話を書きます。
使用できるライブラリ
go git などでぐぐると下記ライブラリがヒットします。サンプルコードを動かすなどしてとりあえず触ってみることに (私のローカルの環境はgo1.6.3かgo1.7を使っています)
GitHub - src-d/go-git: A low level and highly extensible git client library
- source{d}社が作っている
- ライブラリを用いてGitHubのリポジトリを解析しているとのこと
- [Topic Modeling of GitHub Repositories · source{d}](https://blog.sourced.tech/post/github_topic_modeling/
- 解析してトピックモデルLDAなどやっている
GitHub - libgit2/git2go: Git to Go. Like McDonald's but tastier.
src-d/go-gitを試す
READMEには
go get -u gopkg.in/src-d/go-git.v4/...
と v4を go get
して利用するように記載されているのですが、READMEに書かれたコードが動かず、出鼻をくじかれました。
% go run main.go (git)-[master] # gopkg.in/src-d/go-git.v4/plumbing/format/packfile ../../../../../../gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go:158: undefined: io.SeekCurrent ../../../../../../gopkg.in/src-d/go-git.v4/plumbing/format/packfile/scanner.go:314: undefined: io.SeekCurrent
problems install v4 · Issue #107 · src-d/go-git · GitHub こちらに書かれている通り
Hahaha, yes, we only support 1.7, とのことです。goのversionを変えたら正常に動作しました。
go1.6でも、
go get -u gopkg.in/src-d/go-git.v3/...
v3を go get
してくれば無事に動く模様です。
(しかしインターフェースが若干異なるようです)
用例
用例をつらつら書こうと思ったのですが、下記公式の example
がよく整理されています。
go-git/examples at 78516127590ef4a8157f8850be007966b142c1ca · src-d/go-git · GitHub
git pull
でデプロイしている個人プロジェクトがあるので、それらのdeploy用の簡単なツールなど書いてみました。
(shellとかansibleで事足りるんじゃないかという話はあります)
複数の開発用サーバ(ホストに番号が振られている)などに一斉に変更を反映したい場合のツール作りなどに使えそうです (適当に全サーバにはいってgit pullなど)
libgit2/git2goを触る
lib2git自体が必要なので、Macで利用する場合はにhomebrewでdownloadします。
brew install lib2git
Github側にはドキュメントが少ないので godoc
をせっせと読みながら使う感じになります。
git - GoDoc
使い方としてはgit側の使いたい機能を godoc
と lib2git
のドキュメとから引いて対応させていく感じです。
st
package main import ( "fmt" "github.com/libgit2/git2go" ) func main() { repoPath := "path_to_git_repo" r, err := git.OpenRepository(repoPath) if err != nil { panic(r) } // conf := r.Config st, err := r.StatusFile(repoPath) fmt.Printf("%v", st) stlist, err := r.StatusList(&git.StatusOptions{ Flags: git.StatusOptIncludeUntracked, Show: git.StatusShowIndexAndWorkdir, }) if err != nil { panic(err) } fmt.Println("%v", stlist) }
まとめ
lib2gitに依存しないという意味では src-d/go-git
はそれなりに使いやすそうだという感想です。 lib2gitを利用する方がAPIは色々提供されているし(各種バインディングがすでにあることで枯れている)ため、痒いところに手が届かないということはなさそうに見えました。