Upgrade to Pro — share decks privately, control downloads, hide ads and more …

開発効率をあげるgitテクニック / Useful git

buty4649
August 27, 2018

開発効率をあげるgitテクニック / Useful git

2018/08/27にペパボ社内で行われたシェル大活用講座の発表資料です

buty4649

August 27, 2018
Tweet

More Decks by buty4649

Other Decks in Programming

Transcript

  1. 開発効率をあげるgitテクニック
    〜シェル芸もあるよ〜

    View Slide

  2. 高谷雄貴 @buty4649
    シニアエンジニア
    技術部 プラットフォームグループ

    View Slide

  3. git

    View Slide

  4. ● 普段からgitを使っている
    ○ GitHub / GH:E
    ○ GitHub Workflow
    ● gitコマンドを便利にして生産性↑↑
    今日のテーマ

    View Slide

  5. ● gitってなに???って話はしません
    ○ ググるか誰かに聞いてください
    ● bashを使うことを前提で書いている部分があります。
    ○ zsh/fish/bsh/ksh/csh/tcsh/ash/dash な人は適宜読み替えてください
    おことわり

    View Slide

  6. 目次
    1. 減らす
    2. 便利にする

    View Slide

  7. PRを作る場合のオペレーション例
    普段どんなオペレーションをしますか?
    $ git clone [email protected]/foo/bar
    $ cd bar
    $ git checkout -b new-branch

    $ git status
    $ git add foobar
    $ git commit
    $ git push origin new-branch

    1.減らす

    View Slide

  8. PRを作る場合のオペレーション例
    普段どんなオペレーションをしますか?
    $ git clone [email protected]/foo/bar
    $ cd bar
    $ git checkout -b new-branch

    $ git status
    $ git add foobar
    $ git commit
    $ git push origin new-branch

    打鍵数が多い!
    84文字!
    (下線部のみ)
    1.減らす

    View Slide

  9. 減らす

    View Slide

  10. alias g=git

    View Slide

  11. 1.減らす
    ● シェルのエイリアス機能
    ○ コマンドに別名を割り当てる
    ● g で gitコマンドが実行される
    alias g=git

    View Slide

  12. 1. 減らす
    ● 引数はそのまま処理される
    ○ g status は git status として実行される
    ● 引数付きのコマンドもエイリアスにできる
    ○ alias gs=’git status’ とするとgsでgit statusが実行される
    ● エイリアスを消したい場合は unalias コマンドを使う
    ○ unalias g
    ○ 一時的に無効にしたい場合はコマンド名の頭に \ をつける
    ● エイリアスはカレントシェルのみに反映される
    ○ 永続化したい場合は ~/.bash_profile へ
    エイリアス機能の補足

    View Slide

  13. 84文字 → 74文字!!
    エイリアスによって削減
    $ g clone [email protected]/foo/bar
    $ cd bar
    $ g checkout -b new-branch

    $ g status
    $ g add foobar
    $ g commit
    $ g push origin new-branch

    1.減らす

    View Slide

  14. まだ減らす

    View Slide

  15. git config --global alias.st status

    View Slide

  16. 1.減らす
    ● “git” のエイリアス機能
    ○ サブコマンドをにエイリアスをつけられる
    ● よく使うサブコマンドを短い文字にエリアスする
    ○ st → status, a → add など
    ● 設定された内容は ~/.gitconfig に保存される
    ○ ~ は $HOME と同じ意味
    ○ ファイルに設定を書いても良い(即時反映される)
    git config --global alias.st status
    $ cat ~/.gitconfig
    [alias]
    st = status

    View Slide

  17. 1.減らす
    gitサブコマンドのエイリアス例
    $ cat ~/.gitconfig
    [alias]
    a = add
    cl = clone
    cm = commit
    co = checkout
    cob = checkout -b
    p = push
    st = status

    View Slide

  18. 84文字 → 50文字!!
    エイリアスによって削減
    $ g cl [email protected]/foo/bar
    $ cd bar
    $ g cob new-branch

    $ g st
    $ g a foobar
    $ g cm
    $ g p origin new-branch

    1.減らす

    View Slide

  19. 1.減らす
    ● よく使うコマンドを短くすると効果的
    ● 引数を含めよく使うコマンドもエイリアスにする
    ○ サブコマンド+オプションにするとよいと思う
    ○ 例: git checkout -b → git cob
    ● シェルのエイリアスとの使い分け
    ○ シェルのエイリアスにした方がサブコマンドのスペースが減らせる
    ○ 例: alias gcob=’git checkout -b’
    ○ シェルの補完が効かないしコマンド名がかぶる可能性
    ○ 好みの問題かも
    エイリアス作成のコツ(私のやり方)

    View Slide

  20. 1. 減らす
    私の設定例
    [alias]
    br = branch
    cm = commit -v
    cma = commit -v --amend
    cman = commit -v --amend --no-edit
    co = checkout
    cob = checkout -b
    d = diff
    dc = diff --cached
    g = grep
    詳しくは https://github.com/buty4649/dotfiles/blob/master/cookbooks/configfiles/files/.gitconfig

    View Slide

  21. もっと減らす

    View Slide

  22. もっと減らす
    $ g cl [email protected]/foo/bar
    $ cd bar
    $ g cob new-branch

    $ g st
    $ g a foobar
    $ g cm
    $ g p origin new-branch

    1.減らす
    めんどくさい!

    View Slide

  23. 1.減らす
    ● いちいちファイル名を書くのが手間
    ○ git add . でもいいけど、一部だけaddしたい場合不便
    ● 極力ファイル名を打ちたくない!
    ○ 浅い階層ならいいが深い階層だとその分タイプ数が増える
    ファイル名を書くのがめんどくさい!
    どうしたらファイル名を打たずにgit addできるか?

    View Slide

  24. 1.減らす
    ● git addのあとにaddしたいファイル名を羅列する
    ○ git add …
    ● このコマンドを生成できればよい
    ● 変更がかかったファイルはgit statusで取れる
    ● つまり↑をいい感じにしてgit addするスクリプトを書けばよい!
    どうしたらファイル名を打たずにgit addできるか?

    View Slide

  25. 1.減らす
    ● 生のgit statusの結果はパースしづらいのでオプションをつける
    スクリプトを作る
    $ git status --short
    MM file1
    ワークツリーの状態
    インデックスの状態
    M: 変更された A:追加された D:削除された
    U:更新されたがマージされていない(コンフリクトなど)
    ※ 詳しくはgit status --helpを参照

    View Slide

  26. 1.減らす
    ● 出力結果をフィルタする必要がある
    ○ Dなファイルをgit addに渡すとエラーになる
    ○ addしたいファイルのみを選択したい
    ■ コマンドラインセレクターを使うと便利!
    ■ 例えば peco (詳しくはこのあとのudzuraさんの発表で)
    ● スクリプトをどこに書くか?
    ○ gitのエイリアスはスクリプトが書ける
    ○ !を先頭に書くとスクリプトとして解釈される
    ○ 例: v = !vim → git v でvimが起動する
    スクリプトを作る

    View Slide

  27. 1.減らす
    完成したコマンド
    [alias]
    a = !"git status --short | awk '!/^[ADRM] /' | peco
    | awk '{print $NF}' | xargs -r git add"
    git status --short |
    awk '!/^[ADRM] /' |
    peco |
    awk '{print $NF}' |
    xargs -r git add
    先頭がADRMを除外
    ファイルを選択
    ファイル名のみ切り出し
    git addを組み立て

    View Slide

  28. 1.減らす
    解説(awk)
    $ git status --short
    D file1
    M file2
    $ git status --short | awk ‘!/[ADRM] /’
    M file2
    $ git status --short | awk ‘!/[ADRM] /’ |
    > awk ‘{print $NF}’
    file2

    View Slide

  29. 1.減らす
    解説(xargs)
    ● 標準入力をコマンドの引数に追加し実行する
    ○ 例: echo b | xargs echo a → echo a b が実行される
    ● forやwhileでも同じことができる
    ○ 例: date | xargs echo → date | while read LINE;do echo $LINE;done
    ○ サブシェルを作らない分xargsのほうが早い
    ● -r オプションをつけると入力が空の場合実行しない
    ○ macOSのxargsにはないかも…
    ● 通常は末尾に引数を追加するが-Iで任意の場所に追加できる
    ○ -Iに続いて置換する文字列を書く
    ○ 2文字以上でも使える
    ○ 例: date | xargs -I{} echo {} hogehoge
    ● これ以外にもすごく便利なのだけどそれを書くには十分な余白がry

    View Slide

  30. 1.減らす
    これでpushはgit gpushでいけるようになる
    git push origin new-branchも短くする
    [alias]
    gpush = !"git rev-parse --abbrev-ref HEAD | xargs
    git push origin"
    $ git rev-parse --abbrev-ref HEAD
    new-branch

    View Slide

  31. 1.減らす
    これでpushはgit gpushでいけるようになる
    git push origin new-branchも短くする
    [alias]
    gpush = !"git rev-parse --abbrev-ref HEAD | xargs
    git push origin"
    $ git rev-parse --abbrev-ref HEAD
    new-branch

    View Slide

  32. 1.減らす
    ● git push origin HEAD でいける
    ○ この資料を作っているときに知った。。
    ● つまり、↑をエイリアスすればよい
    git push origin new-branchも短くする
    [alias]
    gpush = push orogin HEAD

    View Slide

  33. 1.減らす
    私の設定例
    # ブランチを選択してcheckout
    c = !"git branch | awk '!/^\\*/' | peco | xargs -r git
    checkout"
    # リモートブランチを選択してcheckout
    cobr = !"git branch -r | grep -vE '/(HEAD|master$)' | sed
    -e 's,origin/,,g' | peco | xargs -r -I{} git checkout -b
    {} origin/{}"
    # 変更されたファイルを選択してcheckout
    cof = !"git status --short | peco | awk '{print $2}' |
    xargs -r git checkout --"
    ※ \ はエスケープする必要がある

    View Slide

  34. 84文字 → 29文字!! 65%効率アップ!!!!
    最終結果
    $ g cl [email protected]/foo/bar
    $ cd bar
    $ g cob new-branch

    $ g st
    $ g a
    $ g cm
    $ g gpush

    1.減らす

    View Slide

  35. 目次
    1. 減らす
    2. 便利にする

    View Slide

  36. ● 減らすではタイプ数を減らすことに注力した
    ● 次はタイプ数削減以外の方法で効率化する
    ● 便利なツールや機能を使ってより作業効率をあげる
    2.便利にする

    View Slide

  37. 2.便利にする
    git-completion.bash & git-prompt.sh
    ● gitをインストールするとついてくる便利スクリプト
    ● bashの補完機能を提供
    ○ (brew) /usr/local/etc/bash_completion.d/git-completion.bash
    ○ sourceで読み込む
    ● プロンプトにカレントブランチを表示
    ○ (brew) /usr/local/etc/bash_completion.d/git-prompt.sh
    ○ PS1環境変数に __git_ps1関数を追加する
    $ git branch
    20180827-pepabo-college
    ~/path/to/hoge ( 20180827-pepabo-college )
    $ echo $PS1
    \w$(__git_ps1 " (\[\e[0;31m\]%s\[\e[00m\])")\n\$

    View Slide

  38. 2.便利にする
    ghq
    ● ローカルリポジトリの管理ツール
    ○ https://github.com/motemen/ghq
    ● 指定のディレクトリ配下にgit cloneする
    ○ デフォルトは ~/.ghq
    ○ GOPATHと合わせておくと便利
    ■ git config --global ghq.root ~/src
    ● 使い方
    ○ リモートリポジトリのクローン
    ■ ghq get
    ○ ローカルリポジトリのフルパスを一覧で表示
    ■ ghq list -p

    View Slide

  39. 2.便利にする
    ghq
    ● ghq list と pecoを組み合わせて移動できる
    ○ cd $(ghq list -p | peco)
    ● これをコマンドにする
    ○ 外部コマンドではcdできないので関数で定義する
    ○ 例: gcd() { cd $(ghq list -p | peco); }

    View Slide

  40. 2.便利にする
    tig
    ● TUIなgitクライアント
    ○ https://github.com/jonas/tig
    ● 詳しくはこのあとのjune29の発表で!!!
    ● 私の使い方
    ○ git ll にエイリアスしている
    ○ fixup / squash できるようにしている
    $ cat ~/.gitconfig
    [tig "bind"]
    diff = F ?!git commit --fixup %(commit)
    diff = S ?!git commit --squash %(commit)
    main = F ?!git commit --fixup %(commit)
    main = S ?!git commit --squash %(commit)

    View Slide

  41. 2.便利にする
    hub
    ● Github社が作ったgitコマンドラッパー
    ○ https://github.com/github/hub
    ● gitにエイリアスして使う
    ○ eval $(hub alias -s)
    ● gitに機能を追加する
    ○ issueやPRの作成ができる
    ○ 詳しくは https://hub.github.com/hub.1.html
    ● ローカルリポジトリでhub browseすると便利
    ○ GH:Eなリポジトリを見るときは設定が必要
    ○ git config --global hub.host

    View Slide

  42. 2.便利にする
    git hookを使う
    ● 特定のアクションの実行前/後にスクリプトを実行する
    ○ 詳しくは https://git-scm.com/docs/githooks
    ● hookスクリプトは .git/hooks 配下にある
    ○ 例えばcommit前にhookするなら
    ■ .git/hooks/pre-commit
    ■ chmod +x するのを忘れない(重要)

    View Slide

  43. 2.便利にする
    hook利用例(1): プッシュ前にlintを行う
    ● プッシュした後にCIのlintチェックで落ちると悲しい…
    ● git pushする前にlintすれば回避できる!
    $ cat .git/hooks/pre-push
    #!/bin/bash
    rake lint
    ● しかし、プッシュに時間がかかるようになるというデメリット

    View Slide

  44. 2.便利にする
    hook利用例(2): master pushを防ぐ
    ● master pushやりがち
    ● Github側で設定変更するという手段もある
    ○ すべてのリポジトリに設定するのは手間
    ● hookを使って防ぐ

    View Slide

  45. 2.便利にする
    hook利用例(2): master pushを防ぐ
    https://github.com/buty4649/dotfiles/blob/master/cookbooks/configfiles/files/.git_template/hooks/pre-push
    $ cat .git/hooks/pre-push
    #!/bin/bash
    CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
    if [ "$CURRENT_BRANCH" = "master" ];then
    if [ -z "$ALLOW_GIT_MASTER_PUSH" -a \
    -z "$(git config --get git.allow-master-push)" ];then
    echo "WARN: It's the master branch !!"
    echo 'If you want git push, please set either.'
    echo '* $ALLOW_GIT_MASTER_PUSH=1'
    echo '* git config --local git.allow-master-push 1'
    exit 1
    fi
    fi

    View Slide

  46. 2.便利にする
    hook利用例(2): master pushを防ぐ
    $ git branch
    master
    $ git push
    WARN: It's the master branch !!
    If you want git push, please set either.
    * $ALLOW_GIT_MASTER_PUSH=1
    * git config --local git.allow-master-push 1
    error: failed to push some refs to 'foobar'

    View Slide

  47. 2.便利にする
    hook利用例(2): master pushを防ぐ
    ● master pushしなくなって悲しみが減った
    ● ただ、master pushでもいいときに回避するのが手間
    ○ プロンプトをだしてyを入力したらpushでもいいかも
    ● hookにスクリプトを直接書くと変更するときに面倒
    ○ hookからはコマンドを呼び出すだけにしたほうが良いかも
    ● git init / git cloneの度にhookを配置するのが手間
    ○ git-templateを使うと便利
    ○ https://git-template.readthedocs.io/en/latest/
    ● すでにあるリポジトリに設置したい
    ○ ghq list -p | xargs -L1 -I{} cp -pv pre-push "{}/.git/hooks"
    ○ (自信なし)

    View Slide

  48. まとめ

    View Slide

  49. まとめ
    ● gitコマンドのタイプ数を減らすと効率があがる
    ● シェルスクリプトを駆使してサブコマンドを作ると便利だし楽しい
    ● 便利なツールを使うとより生産性があがる

    View Slide