tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

【go】golangのCLIパッケージ(urfave/cli)を使ってみるメモ

はじめに

command line cliなscriptを作りたいとき、
たいていどの言語でも引数を扱うライブラリがありますよね。

golangではとても便利なurfave/cliというパッケージがあります。
(以前は github.com/codegangsta/cli というリポジトリでした)

この使い方を簡単にメモ

アジェンダ

  1. getting start的な
  2. Arguments とか
  3. Flags 使ってみる
  4. Subcommands でいろいろ

その前に

この記事に使用したソースです。
https://github.com/tweeeety/go-command-line-sample/tree/master/src/script

1. getting start的な

install

go getするだけです。
glide使ってればglide installするだけですね。

$ go get github.com/urfave/cli

使ってみる

前提

これ以降の記述は、すべて以下のようなdir構成になっているものとして進めます。
今回の記事ようにgo-command-line-sampleというプロジェクト ディレクトリを作ってます。

# 作成したgo-command-line-sample
$ pwd
パス/go-command-line-sample

$ tree -L 3 ../go-command-line-sample
../go-command-line-sample
└── src
    └── script # この配下にscriptごとにdirを切る
        ├── glide.lock
        ├── glide.yaml
        └── vendor
簡単に試す

まずはprintするだけ、help出すだけ。
公式と同じですね

src/script/cli_10/main.go
package main

import (
  "10t"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "boom"
  app.Usage = "make an explosive entrance"

  app.Action = func(c *cli.Context) error {
    fmt.Println("boom! I say!")
    return nil
  }

  app.Run(os.Args)
}
実行
# 叩いてみる
$ go run src/script/cli_10/main.go 
boom! I say!

# helpってみる
$ go run src/script/cli_10/main.go help
NAME:
   boom - make an explosive entrance

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   0.0.0

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version
go install

おもむろにgo installしてみます。

# scriptがいる場所まで移動
$ cd src/script/cli_10

# install
$ go instal

# プロジェクト直下にもどる
$ cd パス/go-command-line-sample

# binにcli_10が出来てる
$ tree -L 3
.
├── bin
│   └── cli_10
├── pkg
│   └── darwin_amd64
│       └── script
└── src
    └── script
        ├── cli_10
        ├── glide.lock
        ├── glide.yaml
        └── vendor

# たたいてみる
$ ./bin/cli_10
boom! I say!

ここまで動かすのもめっちゃ簡単ですね!

2. Arguments とか

app := cli.NewApp() した後の基本的な使い方です。

src/script/cli_20/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_20"
  app.Usage = "cli_20 sample"
  app.Version = "1.2.1"

  // before
  app.Before = func(c *cli.Context) error {
    fmt.Println("-- Before --")
    return nil
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")

    fmt.Printf("c.NArg()        : %+v\n", c.NArg())
    fmt.Printf("c.Args()        : %+v\n", c.Args())
    fmt.Printf("c.Args().Get(0) : %+v\n", c.Args().Get(0))
    fmt.Printf("c.Args()[0]     : %+v\n", c.Args()[0])
    fmt.Printf("c.FlagNames     : %+v\n", c.FlagNames())

    // Help表示
    //cli.ShowAppHelp(c) 

    // version表示
    cli.ShowVersion(c) 

    return nil
  }

  // after
  app.After = func(c *cli.Context) error {
    fmt.Println("-- After --")
    return nil
  }

  // true: go run app.go helpと打ってもhelpが出なくなる
  app.HideHelp = true

  app.Run(os.Args)
}
実行
# そのまま実行
$ go run src/script/cli_20/main.go hoge fuga piyo
-- Before --
-- Action --
c.NArg()        : 3
c.Args()        : [hoge fuga piyo]
c.Args().Get(0) : hoge
c.Args()[0]     : hoge
c.FlagNames     : []
cli_20 version 1.2.1
-- After --

# help
$ go run main.go help
-- Before --
NAME:
   cli_20 - cli_20 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   1.2.1

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version
-- After --


# `app.HideHelp = true` なのでhelpは引数として見なされる
$ go run src/script/cli_20/main.go help
-- Before --
-- Action --
c.NArg()        : 1
c.Args()        : [help]
c.Args().Get(0) : help
c.Args()[0]     : help
c.String()      : 
cli_20 version 1.2.1
-- After --
context

c.XXXXで取れるcontextについてはこの辺を見るとかなりたくさんありますね。
https://godoc.org/github.com/urfave/cli#Context

3. Flags 使ってみる

flagsは-lang english-l english的なオプションを受け取るためのものです。
ショートオプションや省略時のdefault optionも指定できます。

command、option、flagとは?というところは以下が大変参考になります。
Go言語によるCLIツール開発とUNIX哲学について

使ってみる

src/script/cli_30/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_30"
  app.Usage = "cli_30 sample"
  app.Version = "1.2.1"

  os.Setenv("SAMPLE_ENV", "sample env dayo")

  // flags
  app.Flags = []cli.Flag{
    cli.StringFlag{
      Name:  "lang, l",
      Value: "english",
      Usage: "language for the greeting",
    },
    cli.StringFlag{
      Name:  "meridian, m",
      Value: "AM",
      Usage: "meridian for the greeting",
    },
    cli.StringFlag{
      Name:  "time, t",
      Value: "07:00",
      // ``で囲むとhelp時のPlaceholderとしても使える
      // https://github.com/urfave/cli#placeholder-values
      Usage: "`your time` for the greeting",
    },
    cli.StringFlag{
      Name:  "aaa, a",
      Value: "sample",
      // default値をValueからではなくEnvから取る
      EnvVar: "SAMPLE_ENV",
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")

    fmt.Printf("c.GlobalFlagNames() : %+v\n", c.GlobalFlagNames())
    fmt.Printf("c.String(\"lang\")    : %+v\n", c.String("lang"))
    fmt.Printf("c.String(\"m\")       : %+v\n", c.String("m"))
    fmt.Printf("c.String(\"time\")    : %+v\n", c.String("time"))
    fmt.Printf("c.String(\"a\")       : %+v\n", c.String("a"))

    return nil
  }

  app.Run(os.Args)
}
実行
# 実行
# 引数のkey:valueはスペースでもイコールでもいける
$ go run src/script/cli_30/main.go -l hoge -m=PM
-- Action --
c.GlobalFlagNames() : [aaa lang meridian time]
c.String("lang")    : hoge
c.String("m")       : PM
c.String("time")    : 07:00
c.String("a")       : sample env dayo

# help
$ go run src/script/cli_30/main.go -h
NAME:
   cli_30 - cli_30 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   1.2.1

COMMANDS:
     help, h  Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --aaa value, -a value           (default: "sample") [$SAMPLE_ENV]
   --lang value, -l value          language for the greeting (default: "english")
   --meridian value, -m value      meridian for the greeting (default: "AM")
   --time your time, -t your time  your time for the greeting (default: "07:00")
   --help, -h                      show help
   --version, -v                   print the version

Flagの種類

Flagとして設定できる種類がいくつかあるのでその例です。
StringFlagBoolFlagが指定できます。

src/script/cli_31/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_31"
  app.Usage = "cli_31 sample"
  app.Version = "1.2.1"

  // flags
  app.Flags = []cli.Flag{
    // StringFlag
    cli.StringFlag{
      Name:  "name, n",
      Value: "tarou",
      Usage: "your name",
    },
    // BoolFlag
    cli.BoolFlag{
      Name:  "gay, g",
      Usage: "are you gay boy?",
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Action --")
    fmt.Printf("c.GlobalFlagNames() : %+v\n", c.GlobalFlagNames())
    fmt.Printf("c.String(\"name\")    : %+v\n", c.String("name"))
    fmt.Printf("c.String(\"g\")       : %+v\n", c.Bool("g"))

    return nil
  }

  app.Run(os.Args)
}

実行
# 指定無しで叩いてみる
$ go run src/script/cli_31/main.go 
-- Action --
c.GlobalFlagNames() : [name gay]
c.String("name")    : tarou
c.String("g")       : false

# 指定有りで叩いてみる
# BoolFlagは、オプションを指定することでtrueとなるFlag
$ go run src/script/cli_31/main.go --name hoge -g
-- Action --
c.GlobalFlagNames() : [name gay]
c.String("name")    : hoge
c.String("g")       : true

4. Subcommands でいろいろ

公式の通りですが、
git-like のようなコマンドが設定できます。

普通に使ってみる

まずは公式のお試し

src/script/cli_40/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_40"
  app.Usage = "cli_40 sample"

  // command action
  // これまでのActionとは違い、flagsごとの挙動(Action)が設定できる
  app.Commands = []cli.Command{
    // `go run cli_40/main.go add パラメータ`でactionするコマンド
    {
      Name:    "add",
      Aliases: []string{"a"},
      Usage:   "add a task to the list",
      Action: func(c *cli.Context) error {
        fmt.Println("added task: ", c.Args().First())
        return nil
      },
    },
    // `go run cli_40/main.go complete パラメータ`でactionするコマンド
    {
      Name:    "complete",
      Aliases: []string{"c"},
      Usage:   "complete a task on the list",
      Action: func(c *cli.Context) error {
        fmt.Println("completed task: ", c.Args().First())
        return nil
      },
    },
    {
      Name:    "template",
      Aliases: []string{"t"},
      Usage:   "options for task templates",
      Subcommands: []cli.Command{
        // `go run cli_40/main.go template add パラメータ`でactionするコマンド
        {
          Name:  "add",
          Usage: "add a new template",
          Action: func(c *cli.Context) error {
            fmt.Println("new task template: ", c.Args().First())
            return nil
          },
        },
        // `go run cli_40/main.go template remove パラメータ`でactionするコマンド
        {
          Name:  "remove",
          Usage: "remove an existing template",
          Action: func(c *cli.Context) error {
            fmt.Println("removed task template: ", c.Args().First())
            return nil
          },
        },
      },
    },
  }

  app.Run(os.Args)
}

実行

実行してみるとこんな感じ

# addコマンドとパラメータで実行
$ go run src/script/cli_40/main.go t add hoge
added task:  hoge

# t(template)コマンドとaddサブコマンドで実行
$ go run src/script/cli_40/main.go t t add hoge
new task template:  hoge

$ go run src/script/cli_40/main.go -h
NAME:
   cli_04 - cli_04 sample

USAGE:
   main [global options] command [command options] [arguments...]

VERSION:
   0.0.0

COMMANDS:
     add, a       add a task to the list
     complete, c  complete a task on the list
     template, t  options for task templates
     help, h      Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

COMMANDStemplateのSubcommandsが表示されないじゃないかーと思いますが
templateまで打って-hすればちゃんと出ます。

かしこい!

$ go run cli_40/main.go t -h
NAME:
   cli_04 template - options for task templates

USAGE:
   cli_04 template command [command options] [arguments...]

COMMANDS:
     add     add a new template
     remove  remove an existing template

OPTIONS:
   --help, -h  show help

before/action/afterとの関係を見る

COMMANDS(のAction)とbefore/action/after らへんはどういう関係で動くか。

src/script/cli_41/main.go
import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_41"
  app.Usage = "cli_41 sample"

  // before
  app.Before = func(c *cli.Context) error {
    fmt.Println("-- Before --")
    return nil
  }

  // command action
  app.Commands = []cli.Command{
    // `go run cli_04/main.go sample パラメータ`でactionするコマンド
    {
      Name:    "sample",
      Aliases: []string{"s"},
      Usage:   "sample task",
      Action: func(c *cli.Context) error {
        fmt.Println("-- Sample Action --")
        fmt.Println("sample task: ", c.Args().First())
        return nil
      },
    },
  }

  // action
  app.Action = func(c *cli.Context) error {
    fmt.Println("-- Nomal Action --")
    return nil
  }

  // after
  app.After = func(c *cli.Context) error {
    fmt.Println("-- After --")
    return nil
  }
  app.Run(os.Args)
}
実行

COMMANDSが渡されたときはapp.Actionは実行されず、
COMMANDSが何も渡されないとapp.Actionが実行されます。

$ go run src/script/cli_41/main.go sample hoge
-- Before --
-- Sample Action --
sample task:  hoge
-- After --

$ go run src/script/cli_41/main.go
-- Before --
-- Nomal Action --
-- After --

c.Commandを見てみる

COMMANDS に指定したAction: func内で使えるc.Commandを見てみます。
こんなのが使えるよー程度ですね。

src/script/cli_42/main.go
package main

import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_42"
  app.Usage = "cli_42 sample"

  // command action
  app.Commands = []cli.Command{
    {
      Name:    "sample",
      Aliases: []string{"s"},
      Usage:   "sample task",
      Action: func(c *cli.Context) error {
        fmt.Println("-- Sample Action --")

        fmt.Printf("c.Command.FullName()        : %+v\n", c.Command.FullName())
        fmt.Printf("c.Command.HasName(\"sample\") : %+v\n", c.Command.HasName("sample"))
        fmt.Printf("c.Command.Names()           : %+v\n", c.Command.Names())
        fmt.Printf("c.Command.VisibleFlags()    : %+v\n", c.Command.VisibleFlags())

        return nil
      },
    },
  }

  app.Run(os.Args)
}
実行
$ go run src/script/cli_42/main.go sample hoge
-- Sample Action --
c.Command.FullName()        : sample
c.Command.HasName("sample") : true
c.Command.Names()           : [sample s]
c.Command.VisibleFlags()    : [--help, -h show help]

Subcommands x Flags

次はSubcommands x Flagsの例です。
Flags単独の例は前述してますが、各Subcommandsごとにも設定できます。

src/script/cli_43/main.go
import (
  "fmt"
  "os"

  "github.com/urfave/cli"
)

func main() {
  app := cli.NewApp()
  app.Name = "cli_43"
  app.Usage = "cli_43 sample"

  // command action
  app.Commands = []cli.Command{
    // addコマンドに対してFlagsを設定
    {
      Name:    "add",
      Aliases: []string{"a"},
      Usage:   "add a task to the list",
      Action: func(c *cli.Context) error {
        fmt.Println("added task: ", c.Args().First())
        fmt.Println("json      : ", c.String("j"))
        fmt.Println("exec      : ", c.String("e"))
        return nil
      },
      Flags: []cli.Flag{
        cli.StringFlag{
          Name:  "json, j",
          Value: "add.json",
        },
        cli.BoolFlag{
          Name: "exec, e",
        },
      },
    },
    // completeコマンドに対してFlagsを設定
    {
      Name:    "complete",
      Aliases: []string{"c"},
      Usage:   "complete a task on the list",
      Action: func(c *cli.Context) error {
        fmt.Println("completed task: ", c.Args().First())
        fmt.Println("csv           : ", c.String("c"))
        fmt.Println("exec          : ", c.String("e"))
        return nil
      },
      Flags: []cli.Flag{
        cli.StringFlag{
          Name:  "csv, c",
          Value: "add.json",
        },
        cli.BoolFlag{
          Name: "exec, e",
        },
      },
    },
  }
  app.Run(os.Args)
}
実行
# addコマンドを実行。addコマンドに指定したFlagsを指定
$ go run src/script/cli_43/main.go add -j test.json -e
added task:  
json      :  test.json
exec      :  true

# addコマンドを実行。completeコマンドに指定したFlagsを指定
# オプションが違うよ、という事でhelpが出る
$ go run src/script/cli_43/main.go add -c test.csv -e
Incorrect Usage: flag provided but not defined: -c

NAME:
   main add - add a task to the list

USAGE:
   main add [command options] [arguments...]

OPTIONS:
   --json value, -j value  (default: "add.json")
   --exec, -e              

# completeコマンドを実行。addコマンドに指定したFlagsを指定
$ go run src/script/cli_43/main.go complete -c test.csv
completed task:  
csv           :  test.csv
exec          :  false

おわり

urfave/cli いろいろてんこもりで便利ですね。
ここまでがっつり機能いらないよって場合は、標準のflag パッケージの方を使ってサクっと作るのも良さそうです
\(^o^)/

【go】direnvで環境(プロジェクトやディレクトリ)ごとに環境変数を分けるメモ - 例:GOPATH

はじめ

golangに限らないですが、
環境ごとに環境変数を切り替えたいときはまぁまぁありますよね。
そんなときのdirenvメモです。

mac x golangな環境を前提に書きますが
direnv自体はlinuxでも他の言語や環境でも同じです。

アジェンダ

  1. direnvとは
  2. direnvのinstall&設定
  3. direnv使ってみる
  4. direnv: error .envrc is blocked. Run direnv allow to approve its content.なとき

1. direnvとは

まずはdirenvのリポジトリ
https://github.com/direnv/direnv

簡単にいうとプロジェクトやディレクトリごとに環境変数を勝手に切り替えてくれる君です。
公式から引用するとこんな感じ。

direnv is an environment switcher for the shell. It knows how to hook into bash, zsh, tcsh and fish shell to load or unload environment variables depending on the current directory. This allows project-specific environment variables without cluttering the “~/.profile” file.

使うとこんな事が可能になります。

* ディレクトリごとにGPATHを設定できる
* ディレクトリへ移動すると自動的に設定される(出ると勝手に解除)

2. direnvのinstall&設定

使う前のinstall&設定。簡単です

# install
$ brew update
$ brew install direnv

# shellに設定
$ echo 'eval "$(direnv hook bash)"' >> ~/.bashrc

3. direnv使ってみる

設定してみる

ここでは環境(ディレクトリ)ごとにGOPATHを切り替える という例で書きますが、他の環境変数でも同じです。

# 移動
$ cd path/to/設定したいディレクトリ

# .envrcを作成
$ direnv edit .
---- vi追記 ----
export GOPATH=$(pwd) 
--------------- 

使い方

# direnvを設定したdir以外にいる前提
$ pwd
path/to/direnv設定してないdir

# 移動
$ cd path/to/設定したdir
direnv: loading .envrc
direnv: export ~GOPATH

# 出てみる
$ cd ..
direnv: unloading

補足

direnv edit .でエラー

direnv edit .するとdirenv: $EDITOR not found なエラーができるときは$EDITORを設定してやります

# 怒られる
$ direnv edit .
direnv: $EDITOR not found.

# bashrcに設定&読み込み
$ echo 'export EDITOR=vim' >> ~/.bashrc
$ source ~/.bashrc

# vimが開けばok
$ direnv edit .

4. direnv: error .envrc is blocked. Run direnv allow to approve its content.なとき

.envrcを直接編集すると以下のようなエラーが出るときがあります。
編集後は安全のためにdirenv allowで明示的に読み込むまでは無効になっているよ、という事らしいです。

# 何かしたらこれがでる
direnv: error .envrc is blocked. Run `direnv allow` to approve its content.

# 素直に打つ
$ direnv allow

参考

終わり

いまさら direnv の解説という記事を参考にさせてもらって
さらに今さら感がありますが自分用メモ>\(^o^)/

【Homebrew】brew updateとbrew upgradeどっちがどっちメモ

はじめに

いつも忘れるのでメモ

違い

参考サイトのまんまですが違いをメモ。

update

Homebrew自体を最新版にして,内部で管理しているformula(パッケージ)も最新版にする

upgrade

Homebrew内部で管理しているformulaのみを最新版にする

参考

もうちょっと詳しく書いてあるので気になる場合は参考サイトをどぞ http://glass5er.hatenablog.com/entry/20121208/1354983531

【go】golangでyamlを読み込んでstructに入れるメモ - gopkg.in/yaml.v2

はじめに

golangyamlを読み込むときのメモ

読み込みたいyaml

userのデータが入ってると仮定したyamlです

sample.yaml
users:
    -   
        name: ほげ ほげ男
        full_name:
            first_name: ほげ
            last_name: ほげ男
        sex: male
        birthday: 1990-12-12
        self_introduction:
            long: ほげほげ男です。よろしくおねがいします!
            short: しゃす!
        image_urls:
            - /my/photo/01.png
            - /my/photo/02.png
            - /my/photo/03.png
        shemale: false
    -   
        name: ふが ふが子
        full_name:
            first_name: ふが
            last_name: ふが子
        sex: female
        birthday: 1994-03-03
        self_introduction:
            long: ふが子です!(≧∀≦*)
        image_urls:
            - /my/photo/01.png
        shemale: true

使うパッケージ

gopkg.in/yaml.v2 というパッケージを使います。

go getで取得すればいけるはず

$ go get gopkg.in/yaml.v2

今回はglideで入れました

構成

sample.yaml が読み込みたいyamlです。
glideな関係でmainのコードはsrc/go-yaml-sample/yaml_sample.goとなってます。

$ pwd
プロジェクトdir

$ tree -L 3
.
├── sample.yaml
└── src
    └── yaml_sample
        ├── glide.lock
        ├── glide.yaml
        ├── vendor
        └── yaml_sample.go

コード

gopkg.in/yaml.v2 を使うと、json.Marshalな感じでyamlを読み込んでくれます。

src/go-yaml-sample/yaml_sample.go
package main

import (
  "fmt"
  "io/ioutil"

  yaml "gopkg.in/yaml.v2"
)

// structたち
type Data struct {
  Users []User `yaml:"users"`
}

type User struct {
  Name             string           `yaml:"common"`
  FullName         fullName         `yaml:"full_name"`
  Sex              string           `yaml:"sex"`
  SelfIntroduction selfIntroduction `yaml:"self_introduction"`
  ImageURLs        []string         `yaml:"image_urls"`
  Shemale          bool             `yaml:"shemale"`
}

type fullName struct {
  FirstName string `yaml:"first_name"`
  LastName  string `yaml:"last_name"`
}

type selfIntroduction struct {
  Long  string `yaml:"long"`
  Short string `yaml:"short"`
}

func main() {
  // yamlを読み込む
  buf, err := ioutil.ReadFile("../../sample.yaml")
  if err != nil {
    panic(err)
  }
  fmt.Printf("buf: %+v\n", string(buf))

  // structにUnmasrshal
  var d Data
  err = yaml.Unmarshal(buf, &d)
  if err != nil {
    panic(err)
  }
  fmt.Printf("d: %+v", d)

}
結果
$ cd src/yaml_sample/

$ go run yaml_sample.go 
buf: users:
    -
        name: ほげ ほげ男
        full_name:
            first_name: ほげ
            last_name: ほげ男
        sex: male
        birthday: 1990-12-12
        self_introduction:
            long: ほげほげ男です。よろしくおねがいします!
            short: しゃす!
        image_urls:
            - /my/photo/01.png
            - /my/photo/02.png
            - /my/photo/03.png
        shemale: false
    -
        name: ふが ふが子
        full_name:
            first_name: ふが
            last_name: ふが子
        sex: female
        birthday: 1994-03-03
        self_introduction:
            long: ふが子です!(≧∀≦*)
        image_urls:
            - /my/photo/01.png
        shemale: true


d: {Users:[{Name: FullName:{FirstName:ほげ LastName:ほげ男} Sex:male SelfIntroduction:{Long:ほげほげ男です。よろしくおねがいします! Short:しゃす!} ImageURLs:[/my/photo/01.png /my/photo/02.png /my/photo/03.png] Shemale:false} {Name: FullName:{FirstName:ふが LastName:ふが子} Sex:female SelfIntroduction:{Long:ふが子です!(≧∀≦*) Short:} ImageURLs:[/my/photo/01.png] Shemale:true}]}

リポジトリ

おわり

yamlもサクっと簡単!\(^o^)/

【git】git tagを取り消す

はじめに

git tagを取り消すメモ。 ほとんど手順メモ程度な感じ+他記事で使うスニペット記事。

補足

他の取り消しもぱっと見たい自分用にまとめたので参考までに。

【git】add、commit、push、merge、pull request、merge pull request、tagの取り消し

アジェンダ

  1. localでの取り消し(削除)
  2. リモートでの取り消し

1. localでの取り消し(削除)

ローカルで消す場合は git tag -d タグ とします。

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5

$ git tag v1.0.6

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5
v1.0.6

$ git tag -d v1.0.6
Deleted tag 'v1.0.6' (was 7bd2f6b)

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5safdsa

2. リモートでの取り消し

リモートのtagを消す場合は git push origin :refs/tags/タグ とします。
ローカルを先に消す必要も無いし、localのが一緒に消えるわけでもないです。

# リモートのタグを確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5
7bd2f6b05c73cc1042d0b9b8b311e96d3375b13f  refs/tags/v1.0.6

# リモートのタグを削除
$ git push origin :refs/tags/v1.0.6
To https://github.com/tweeeety/git-tag-sample.git
 - [deleted]         v1.0.6

# 消えてるか確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5

# ローカルには残ってるので別途消してね
$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5
v1.0.6

終わり

git ls-remote --tags のほうを忘れそうw

【git】git tagの使い方をかんたんにおさらい

はじめに

リリース管理やブランチ管理にはまぁまぁ利用するgit tagですがおさらいがてらにメモ

アジェンダ

  1. git tagとは
  2. よく使うgit tagコマンド
  3. tagの作成
  4. tagの一覧
  5. tagの確認
  6. tagの削除
  7. tagのpush
  8. リモートのタグの一覧
  9. リモートのタグの削除

1. git tagとは

タグとは、コミットを参照しやすくするために、わかりやすい名前を付けるものです。

Gitでは、軽量タグと、注釈付きタグの2種類のタグが使用できます。また、一度付けたタグはブランチのように位置が移動することはなく固定です。

説明下手なので参考サイトから引用させていただきました。 * http://www.backlog.jp/git-guide/stepup/stepup4_1.html

2. よく使うgit tagコマンド

あんちょこ的に先にまとめておきます。
コマンドベースでざっとできる事を羅列

# tagの作成
$ git tag タグ
$ git tag -a タグ -m "こめんと"

# tagの一覧
$ git tag

# リモートのタグの一覧
$ git ls-remote --tags

# tagの確認
$ git show タグ

# tagの削除
$ git tag -d タグ

# tagのpush
$ git tag push タグ
$ git push --tags

3. tagの作成

軽量タグの作成

コマンド

git tag タグ

$ git tag v1.0.0

注釈付きタグの作成

コマンド

git tag -a タグ -m ‘コメント’

$ git tag -a v1.0.0 -m 'add readme'

タグをあとからつける

コマンド

git tag -a タグ -m ‘コメント’ コミットハッシュ

$ git tag -a v1.0.0 -m "add readme" 6d0a343aa89b63f6d01116116afcca30c7250ed1

4. tagの一覧

コマンド

git tag

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.3

5. tagの確認

コマンド

git show タグ

$ git show v1.0.0
tag v1.0.0
Tagger: tweeeety <tweeeety.0719@gmail.com>
Date:   Mon May 8 23:09:11 2017 +0900

add readme

commit 6d0a343aa89b63f6d01116116afcca30c7250ed1
Author: tweeeety <tweeeety.0719@gmail.com>
Date:   Wed Apr 19 21:58:44 2017 +0900

    first commit

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..71d9d7a
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# git-tag-sample

6. tagの削除

コマンド

git tag -d タグ

$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.3

$ git tag -d v1.0.3
Deleted tag 'v1.0.3' (was 8bfcc5a)

$ git tag
v1.0.0
v1.0.1
v1.0.2

7. tagのpush

個別にpush

コマンド

git push origin タグ

$ git push origin v1.0.2
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 525 bytes | 0 bytes/s, done.
Total 6 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1), done.
To https://github.com/tweeeety/git-tag-sample.git
 * [new tag]         v1.0.2 -> v1.0.2
補足

タグv1.0.2は一番最後のcommit(8bfcc5aa8eab54d20b46864595de4e8b992c4479)に対してつけたもの。 最初のcommitから最後までpushを一度もしてないままに、
git push origin v1.0.2 とする事もできる。

$ git log
commit 8bfcc5aa8eab54d20b46864595de4e8b992c4479
Author: tweeeety <tweeeety.0719@gmail.com>
Date:   Mon May 8 23:11:22 2017 +0900

    modify third

commit 0715d6e897c84b003ee3f1d9833bfe23d0023355
Author: tweeeety <tweeeety.0719@gmail.com>
Date:   Mon May 8 23:10:42 2017 +0900

    modify second

commit 08c9f32c3f36a7577366440f24b095a697c8645d
Author: tweeeety <tweeeety.0719@gmail.com>
Date:   Mon May 8 23:07:55 2017 +0900

    modify first

commit 6d0a343aa89b63f6d01116116afcca30c7250ed1
Author: tweeeety <tweeeety.0719@gmail.com>
Date:   Wed Apr 19 21:58:44 2017 +0900

    first commit

まとめてpush

それまでpushされてないlocalで作成済みのtagがまとめてpushされます

コマンド

git push –tags

$ git push --tags
Counting objects: 12, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 509 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), completed with 1 local object.
To https://github.com/tweeeety/git-tag-sample.git
 * [new tag]         v1.0.2 -> v1.0.2
 * [new tag]         v1.0.4 -> v1.0.4
 * [new tag]         v1.0.5 -> v1.0.5

8. リモートのタグの一覧

commitとの紐付けも見れて便利

コマンド

git ls-remote –tags

$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5

9. リモートのタグの削除

コマンド

git push origin :refs/tags/タグ

# リモートのタグを確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5
7bd2f6b05c73cc1042d0b9b8b311e96d3375b13f  refs/tags/v1.0.6

# リモートのタグを削除
$ git push origin :refs/tags/v1.0.6
To https://github.com/tweeeety/git-tag-sample.git
 - [deleted]         v1.0.6

# 消えてるか確認
$ git ls-remote --tags
From https://github.com/tweeeety/git-tag-sample.git
6d0a343aa89b63f6d01116116afcca30c7250ed1  refs/tags/v1.0.0
08c9f32c3f36a7577366440f24b095a697c8645d  refs/tags/v1.0.1
0715d6e897c84b003ee3f1d9833bfe23d0023355  refs/tags/v1.0.2
063adbe5ed48fc19dbea5d92491995e09ad762f2  refs/tags/v1.0.4
33ed691e1c4363b4b5cf7f102fab3ca27f5ba5ab  refs/tags/v1.0.5

# ローカルには残ってるので別途消してね
$ git tag
v1.0.0
v1.0.1
v1.0.2
v1.0.4
v1.0.5
v1.0.6

リポジトリ

https://github.com/tweeeety/git-tag-sample

終わり

おさらいというかあんちょこ的になったけど、それはそれで良し\(^o^)/

【git】最初のgit commitを取り消す - `git update-ref -d HEAD`もしくは`git filter-branch`

はじめに

以前、【git】git commitを取り消すという記事を書きました。

git reset xxxで普段のcommitの取り消しは問題なくできますが、
そのリポジトリで1発目のcommitの取り消しができません。

たとえばこんな時ありますよね。
「あ、間違ってauthor違う名前でcommitしちゃった。取り消して設定しなおそ」
みたいな。

そんな時のメモ

補足

他の取り消しもぱっと見たい自分用にまとめたので参考までに。

内容

  1. git reset xxxでcommit取り消しできない例
  2. git update-ref -d HEAD でcommit取り消しできる例
  3. git update-ref -d HEAD でcommit取り消したがgithub上は違う方法で変えなきゃな例

1. git reset xxxでcommit取り消しできない例

リポジトリを作成し、1発目にcommitしたものを取り消します。

# log確認。当然1つしかない
$ git log
commit 5646f5ca182c74329094f89c888d80f6b3de92fa
Author: hogehoge <hogehoge>
Date:   Fri Apr 14 22:32:41 2017 +0900

    first commit

# reset --soft HEAD^で1つ前を取り消そうと思ったけどできない
$ git reset --soft HEAD^
fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

2. git update-ref -d HEAD でcommit取り消しできる例

章題に書いてますが、git update-ref -d HEAD でできます。

# log確認。当然1つしかない
$ git log
commit 5646f5ca182c74329094f89c888d80f6b3de92fa
Author: hogehoge <hogehoge>
Date:   Fri Apr 14 22:32:41 2017 +0900

    first commit

# 
$ git update-ref -d HEAD

# 無事リセットされてる
$ git log
git log
fatal: bad default revision 'HEAD'

git update-ref についてはあまり調べてませんが、参照を更新するコマンドらしいです。

3. git update-ref -d HEAD でcommit取り消したがgithub上は違う方法で変えなきゃな例

2の項目で一見落着な感じでしたが、
これはlocalで行った操作が git add / git commit のみの場合です。

git push してgithub上にpushしてしまった場合は、以下の方法で変える必要があります。
※ ここは以前書いたのではしょりました

おわり

慣れてるつもりでもあんまりやらない操作だと
わからない事はまだまだ多いですね\(^o^)/