gitで便利なエイリアス達

これは[Git Advent Calendar / Jun. - Qiita](http://qiita.com/advent-calendar/git).16日目の記事です．

私はエイリアスが好きなのでgitまわりのエイリアスについて書いてみます．
間違ってたらすみません，指摘してくださると嬉しいです．

# 設定方法
いろんなスコープにエイリアスを設定できます．
例として`git st`で`git status`を実行できるようにしてみましょう．
設定ファイルに書き込む方法と，`git config`コマンドで設定する方法があります．
設定ファイルに書く場合は以下のように`alias`セクションに`短縮形 = 展開形`の書式で書きます．

```
[alias]
	st = status
```

どの設定ファイルに書くかで適用される範囲が変わります．
また，コマンドで設定する場合は，`git config [option] alias.短縮形 展開形`を実行します．

- マシン全体に反映させる場合

`$(prefix)/etc/gitconfig`に書くか，以下のコマンドを実行します．

```sh
% git config --system alias.st status
```

- ユーザ単位で反映させる場合

`~/.gitconfig`に書くか，以下のコマンドを実行します．

```sh
% git config --global alias.st status
```


- リポジトリ単位で反映させる場合

`.git/config`に書くか，以下のコマンドを実行します．

```sh
% git config alias.st status
```

## 優先順位

マシンよりユーザ，ユーザよりリポジトリが優先されます．

# ぺっくの使ってる設定例

```:~/.gitconfig
[alias]
        # いい感じのグラフでログを表示
	graph = log --graph --date=short --decorate=short --pretty=format:'%Cgreen%h %Creset%cd %Cblue%cn %Cred%d %Creset%s'
        # 上の省略形
	gr = log --graph --date=short --decorate=short --pretty=format:'%Cgreen%h %Creset%cd %Cblue%cn %Cred%d %Creset%s'
	st = status
	cm = commit
        # Untracked filesを表示せず，not stagedと，stagedだけの状態を出力する
	stt = status -uno
        # 行ごとの差分じゃなくて，単語レベルでの差分を色付きで表示する
	difff = diff --word-diff
```

さらに私の場合はシェルのエイリアスにもこんな感じで設定してgitすら省略しています．

```:~/.alias
alias pull='git pull'
alias push='git push'
alias st='git status'
alias stt='git status -uno'
```

# その他の便利そうな話

- 外部コマンド

gitじゃない外部コマンドもエイリアスで実行できます．例えば`git hoge`で`echo hogehoge`が実行されるようにするには，

```
[alias]
        hoge = !echo hogehoge
```

のように`!`を展開形の前につけると，"git"を取って展開したコマンドを実行できます．

- 内部コマンド

あと，既に存在するコマンドを上書きするようなエイリアスは無視されるそうです．例えば

```
[alias]
        status = some other command
```

みたいなのはだめってことだと思います．

- 引数の区切り

展開形の引数の区切りはスペースで，一般的なシェルでのクォートとかエスケープがサポートされてるそうです．

# 参考

```sh
% man git-config
% git help config
```

# 最後に

皆さんの使ってるエイリアスが知りたいのでコメントにいっぱい集まればいいなーなんて

# 2015/07/23 追記
あれから数年が経ち、いろいろ設定が増えていました。

```:~/.gitconfig
    # ファイル名のみの差分を表示する
    difff = diff --name-only
    # staged diff
    diffs = diff --cached
    dp = diff --no-prefix
    dsp = diff --cached --no-prefix
    co = checkout
    logg = log --graph --all --decorate
    log1 = log --pretty='format:%C(yellow)%h%Creset %C(magenta)%cd%Creset %s %Cgreen(%an)%Creset %Cred%d%Creset%C(black bold)%ar%Creset' --date=iso
    # lg = log --graph --pretty=format:'%Cred%h%Creset - %s%C(yellow)%d%Creset %Cgreen(%cr:%cd) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
    lg = log --graph --pretty=format:'%Cred%h%Creset - %s%C(yellow)%d%Creset %Cgreen(%cr:%cd) %C(bold blue)<%an>%Creset' --abbrev-commit --date=iso
    lga = !"git lg --all"
    log0 = log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(bold white)― %an%C(reset)%C(bold yellow)%d%C(reset)' --abbrev-commit --date=relative
    log2 = log --graph --all --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(bold white)― %an%C(reset)' --abbrev-commit
    log3 = log --graph --date-order -C -M --pretty=format:"<%h> %ad [%an] %Cgreen%d%Creset %s" --all --date=short
    log4 = log --graph --pretty='format:%C(yellow)%h%Cblue%d%Creset %s %C(black bold)%an, %ar%Creset'
    sgraph = !"git log --oneline --graph"
    ancestor = !zsh -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -n 1' -
    unstage = reset HEAD
```


```:~/.alias
alias git-submodule-rm="git rm-submodule --no-commit"
# 上のgitconfigで定義したもの
alias gitu="git unstage"
alias reb='git svn rebase'
alias gl="git clone"
# リモートからフェッチ(タグを更新し、削除済みブランチを削除)してpullする
alias gu="git fetch --tags --prune&& git pull origin"
```

# 2015/12/09 追記

cherry-pickがめんどくさくなりました。

```
  cp = cherry-pick
```

# 2016/02/16 追記

git flow、git stash用のエイリアスを追加しました。

```
    ffs = flow feature start
    sp = stash pop
    ss = stash save
```

# 2016/08/23 追記

branch 長い。

```
    b = branch
```

# 2016/08/28 追記
現在のブランチ名を取得する。

使い方

`git push origin $(tb)`

```:~/.alias
# this branch
alias tb="git symbolic-ref --short HEAD|tr -d \"\\n\""
```

# 2017/02/07 追記
Git LFSのステータスを確認する。

使い方

`git stl`
`stl`

`st`と組み合わせて、`st; stl` みたいに使い始めました。

```:~/.alias
alias stl='git lfs status'
```

```:~/.gitconfig
    stl = lfs status
```

# 2018/02/26 追記
リモートブランチをpercolでインクリメンタル検索して選んでcheckoutする。
プルリクが溜まってくると選ぶときにhelm/anythingライクに絞り込みたくなる。

```:~/.gitconfig
    cob = !"git branch -r|sed -e 's/origin\\///'|percol|xargs git checkout"
```
要[percol](https://github.com/mooz/percol)。きっと類似ツールでも実現可能。


# 2018/06/22 追記
現在のブランチ名(**B**ranch **N**ame)を出力する

```:~/.gitconfig
    bn = rev-parse --abbrev-ref HEAD
    # 最後の改行文字を消すならこちら
    # bn = !"git rev-parse --abbrev-ref HEAD|tr -d \\\\r\\\\n"
```

# 2019/04/26 追記
ブランチ名やタグ名、HEADなどがついたコミットだけをグラフ表示する
(**B**ranch **G**raph)

```:~/.gitconfig
    # branch or tag only graph
    # https://stackoverflow.com/a/9726638/514411
    bg = log --graph --simplify-by-decoration --pretty=format:'%d' --all

```

参考: https://stackoverflow.com/a/9726638/514411

# 2019/08/22 追記
git switch, git restoreが追加されましたね [gitに新しいサブコマンドが追加された (ブランチ切り替え: switch, ファイルを戻す: restore) - @peccul is peccu](http://peccu.hatenablog.com/entry/2019/08/20/000000)
私は `git co`や`gitco`で解決しちゃうので乗り換えられなさそうですが。。。

fzfを使う設定を追加 from [git操作はGUIツール派な自分もCUIに乗り換えた便利git拡張まとめ - Qiita](https://qiita.com/yukiarrr/items/9c21d97f6c8ac31de157)
stash関連は1文字抜いてます。

```sh
    # ファイル別にdiffを見る
    d = "!f() { args=$@; [ -z \"$args\" ] && args=HEAD; ([ \"$args\" = \"HEAD\" ] && git status --short || git diff --name-status $args | sed 's/\t/  /') | fzf --preview \"echo {} | cut -c 4- | xargs git diff --color=always $args --\" --multi --height 90% | cut -c 4-; }; f"
    # ブランチ名を絞り込んで切り替える
    co = "!f() { args=$@; if [ -z \"$args\" ]; then branch=$(git branch --all | grep -v HEAD | fzf --preview 'echo {} | cut -c 3- | xargs git log --color=always' | cut -c 3-); git checkout $(echo $branch | sed 's#remotes/[^/]*/##'); else git checkout $args; fi }; f"
    # stash listでパッチもプレビュー
    sl = !git stash list | fzf --preview 'echo {} | grep -o stash@{.*} | xargs git stash show -p --color=always' --height 90% | grep -o stash@{.*}
    # ↑でプレビューした後にapply
    sa = !git sl | xargs git stash apply
    # ↑でプレビューした後にdrop
    sd = !git sl | xargs git stash drop
```

# 2020/03/10 追記

### マージ済みブランチをまとめて消す

エイリアスとはちょっと違いますがマージ済みブランチを消すサブコマンドを作りました。
`git-db`という名前で実行権限をつけてパスの通ったところにおけば使えます。

プルリクを出した後にマージされるとローカルにブランチがたまるのでそれをまとめて消すのに使っています。

```sh:git-db
#!/bin/zsh
git pull && git fetch --tags --prune && git branch --merged=$(git bn) | grep -vE 'develop|master|$(git bn)' | xargs git branch -d
```

`git-*`という名前の実行ファイルがあるとgitのサブコマンドとして利用できるので実質エイリアスのようになります。
↑のサブコマンドは `git db` で利用できます。

### 現在のブランチでプルリクを作る

hubコマンドとか使えばいいのかもしれませんが、GitBucketで使えなさそうでめんどくさかったので。

リモートのURLからプルリク作成画面のURLを作っています。

https://github.com/owner/repo.git
↓
https://github.com/owner/repo/compare/XXXX...YYYY?expand=1

XXXXにgit flowの開発ブランチを、YYYYに現在のブランチを埋め込んでいます。

```sh
    pr = !"open \"$(git remote get-url origin |sed 's/\\/git\\//\\//;s/\\.git$/\\/compare\\//')$(git config gitflow.branch.develop|tr -d \\\\r\\\\n)...$(git rev-parse --abbrev-ref HEAD|tr -d \\\\r\\\\n)?expand=1\""
```

openはmac用なので、windowsならstartなどを指定してください。