14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CAMPFIREAdvent Calendar 2020

Day 3

Goで不要なブランチを削除するコマンドラインツールを作ってみた

Last updated at Posted at 2020-12-02

少し前にGoの勉強用で不要なブランチを削除するコマンドラインツールを作ったので簡単にまとめてみます。実際に作ったものはこちらです。
https://github.com/yuzoiwasaki/sweep

使い方

こんな感じで不要なブランチを削除できます。

masterブランチ以外を削除

$ git branch
* master
  test1
  test2
$ sweep
$ git branch
* master

test1ブランチ以外を削除

$ git branch
* master
  test1
  test2
$ sweep -v test1
$ git branch
* test1

test1ブランチとmasterブランチ以外を削除

$ git branch
* master
  test1
  test2
$ sweep -v test1 -v master
$ git branch
* master
  test1

なぜ作ろうと思ったか

Goでコマンドラインツールを作ってみようと思った時に、せっかくなら自分がほしいものを作りたかったからです。

ブランチの削除自体はワンライナーでできますし、エイリアスに登録しておけば毎回わざわざ長いコマンドを入力する必要もないのですが、エイリアスも面倒なのでこういうツールがあっても良いのではないかと思いました。

なんにせよ、何かを作ろうと思った時に自分のほしいものを作るというのは良いモチベーションだと思います(自分がほしいということは、もしかしたら他の人もほしいかもしれないですし)

コード全体

コード全体としてはこんな感じのコードになります。コマンドラインから引数を受け取って処理した後、シェルコマンドを呼び出すシンプルな構造です。

sweep.go
package main

import (
	"flag"
	"fmt"
	"os/exec"
)

type strslice []string

func (s *strslice) String() string {
	return fmt.Sprintf("%v", multiflag)
}

func (s *strslice) Set(v string) error {
	*s = append(*s, v)
	return nil
}

var multiflag strslice

func main() {
	flag.Var(&multiflag, "v", "Specify the branch you want to exclude")
	flag.Parse()

	if len(multiflag) == 0 {
		multiflag = append(multiflag, "master")
	}

	var b, e string

	for _, s := range multiflag {
		b = s
		e = e + " | grep -v " + s
	}
	cmdstr := "git checkout " + b + " && git branch" + e + " | xargs git branch -D"

	err := exec.Command("sh", "-c", cmdstr).Run()
	if err != nil {
		fmt.Printf("Error! Failed to sweep branches.\n")
	}
}

Goには flag というコマンドラインオプションをパースできるパッケージがあるので、こちらを使って引数を受け取り処理をしています。
https://golang.org/pkg/flag/

また、最終的にはOS上でシェルコマンドを実行したかったため、合わせて os/exec もインポートしています。

悩んだところ

flag は便利なのですが、そのままでは同じオプションに対して複数の値を受け取ってパースすることができません。これを実現するためには、少し独自に拡張する必要があります。

flagflag.Var() を使うことで独自型の変数をバインドすることができます。また flag には Value というインターフェースが定義されているため、このインターフェースを満たす形で型を定義してあげることで独自に拡張することができます。便利ですね。

you can create custom flags that satisfy the Value interface (with pointer receivers) and couple them to flag parsing by

flag.Var(&flagVal, "name", "help message for flagname")

・参考
https://qiita.com/hironobu_s/items/96e8397ec453dfb976d4
https://golang.org/pkg/flag/#Value

終わりに

以上、簡単ではありますがGoでコマンドラインツールを作ってみた紹介でした。もしよければ使ってみてください。

拙作ですが、同じように初めてGoでツールを作る人の参考になれば嬉しいです。今のところ仕事でGoを使う予定はないのですが、これからも趣味で触っていきたいと思います。

14
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?