Git - コマンドラインTips

コマンドライン(Bash,Unixコマンドを想定)でGitを触る方のために、筆者が実際に行っている設定や使い方を紹介します。実際に開発で使いながら自分に合った使い方をしていただければと思います。

Gitの基本やブランチモデルとか管理の仕方は、最初に紹介する書籍を読んでいただければと思います。本記事ではコマンドライン操作するのに便利なBashの機能や簡単なTipsを紹介します。

# Pro Git
Gitの解説書がCreative Commonsライセンスで公開されています。
前半だけでも読んでください。
[Pro Git 日本語版電子書籍公開サイト](https://progit-ja.github.io/)

解説書の最初の方に書いてありますが、Gitをコマンドラインから使うべき理由が2つあります。

- コマンドラインでのみ、Gitのすべての機能を実行することができる。
- 作業の標準化ができる。公式サイトを始めGitを説明するときはコマンドラインでの解説が多い。

# Bash

動作確認環境です。
開発現場ではWindows端末が貸与されているので、Git for Windowsを使用しています。

```shell
$ uname -a
Linux laputa 4.19.4-arch1-1-ARCH ＃1 SMP PREEMPT Fri Nov 23 09:06:58 UTC 2018 x86_64 GNU/Linux

$ bash --version
GNU bash, version 4.4.23(1)-release (x86_64-unknown-linux-gnu)
...
```

# config --global

`git config --global`
ローカルにあるどのリポジトリでも使えるGitの設定ができます。
以下の例ではデフォルトのユーザー名とメールアドレスを設定しています。

```bash
$ git config --global user.name takayu90
$ git config --global user.email example@gmail.com
```

global設定で紹介したいのは、alias(エイリアス)です。
よく使うコマンドは全部打鍵するのが面倒なので短い名前にしておくと作業が楽になります。

```bash
$ git config --global alias.co checkout
$ git config --global alias.st status
$ git config --global alias.br branch
```

これにより、`git checkout`の代わりに`git co`でチェックアウトコマンドを実行することができます。

ユーザーの設定もエイリアスもすべて`~/.gitconfig`ファイルに保存されます。
このファイルを削除するとglobal設定がすべて削除されてしまいます。
コマンドで設定せずに直接ファイルを編集しても構いません。

```:~/.gitconfig
[user]
  name = takayu90
  email = sample@gmail.com
[alias]
  co = checkout
  st = status  
  br = branch  
```

# UNIXコマンド
知っておくべきシェル機能・コマンドを紹介します。

## ショートカットキー
Bashコマンドライン操作の基本です。使いながら慣れましょう。
[Bashショートカットキー](https://qiita.com/takayu90/items/011a674b0a903572a50c)

特に`Ctrl + p`(直前のコマンドを入力)と`Ctrl + r`(コマンド実行履歴検索)はよく使います。

## find, locate
logやdiffなどでファイルを指定するときに、階層が深いファイル名は以下のコマンドで出力された結果をコピー&ペーストすると速いです。
`find`: ファイルの相対パスを取得できる
`locate`: 事前に作成されたファイル名のDBからファイルのフルパスを取得できる

```
$ find -name "example.py"
./aaa/bbb/ccc/ddd/example.py

$ locate "example.py"
/home/takayu90/example/aaa/bbb/ccc/ddd/example.py
```

`locate`コマンドを使うためには、その前に`updatedb`コマンドを実行してデータベースファイルを更新しておく必要があります。
また、システム全体から一致するファイルを検索しますので複数の検索結果が表示されることもあります。(findも同様)
(Git for Windowsでは使えない。。)

Linux環境であればxselなどでコピーするといいでしょう。

## less
`log`や`diff`コマンドで結果が長いときに使われるページャです。
以下のように操作します。
`h`: ヘルプを表示する
`q`: 終了
`j`: 1行下へ
`k`: 1行上へ
`d`: down 半ページ分下へ
`u`: up   半ページ分上へ
`f`: forward 1ページ分下へ
`b`: back    1ページ分上へ
`gg`: 一番最初へ
`/`: 文字列検索
`n`: 検索した文字列にマッチする箇所に順に移動する

## エディタ
`git commit`や`git rebase -i`などを使うとエディタが開きます。
デフォルトのエディタはviですが、設定によって変更することができるので説明は省略します。
いずれにしてもCUIベースのエディタに慣れておくと役に立ちます。

# log - ログ
コミットログを参照します。
様々な情報を含んでいますので、用途に合わせてオプションを使いましょう。
`git log`コマンドだけだと以下のような出力になります。

```bash
commit cdb829d6e182731603e50ae1e2bcefa587ac571c (HEAD -> develop, origin/develop)
Merge: bf0d6ae f52b08a
Author: master user <master@gmail.com>
Date:   Fri Nov 30 00:24:03 2018 +0900

    Merge branch 'feature/example' into develop

commit f52b08a497369a1c02b20676b9388ebe751152a9
Author: takayu90 <takayu90@gmail.com>
Date:   Fri Nov 30 00:21:08 2018 +0900

    example commit
...
```

様々なオプションがありますが、個人的によく使うオプションです。
`--oneline`: ログを1行で出力する。
`--numstat`: 変更されたファイルを追加・削除行数と共に表示する。
`--graph`: ツリーみたいに表示する。
`--all`: すべてのブランチのコミットを表示する。
`-1`: 指定した数だけの直近のコミットを表示する。
`--no-merges`: マージコミットは表示しない。
`-p`: どのような変更があったのか差分を表示していく。例)`git log -p README.md`でREADME.mdに加えられた変更を見ることができる。

よく使っているlogコマンドです。
フォーマットを指定して色付けしています。(pretty=formatでログのフォーマットをカスタマイズします)

```bash
$ git log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s'
$ git log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s' --graph
$ git log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s' --numstat
$ git log --graph --oneline
```

長い!のでこういうのをエイリアスにします。

```
[alias]
  ...
  oneline = "log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s'"
  graph = "log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s' --graph"
  numstat = "log --date=format:'%y-%m-%d %H:%M' --pretty=format:'%C(yellow)%h%C(reset) %ad %C(green)%an%C(reset) : %s' --numstat"
  gphone = "log --graph --oneline"
```

こんな表示になります。※色は反映されていません。
カスタマイズして自分に合ったlogコマンドをつくりましょう。

```bash
$ git oneline
cdb829d 18-11-30 00:24 master user : Merge branch 'feature/example' into develop
f52b08a 18-11-30 00:21 takayu90 : example commit
bf0d6ae 18-11-18 16:08 master user : Merge branch 'hotfix/999' into develop
7f224cc 18-11-18 16:04 takayu90 : bugfix...
...
```
```bash
$ git graph
*   cdb829d 18-11-30 00:24 master user : Merge branch 'feature/example' into develop
|\
| * f52b08a 18-11-30 00:21 takayu90 : example commit
|/
*   bf0d6ae 18-11-18 16:08 master user : Merge branch 'hotfix/999' into develop
|\
| * 7f224cc 18-11-18 16:04 takayu90 : bugfix...
...
```
```bash
$ git numstat # バイナリファイルは変更行数はでません
cdb829d 18-11-30 00:24 master user : Merge branch 'feature/example' into develop
f52b08a 18-11-30 00:21 takayu90 : example commit
-       -       aaa/bbb/ccc/example
15      0       aaa/bbb/ccc/example.js

bf0d6ae 18-11-18 16:08 takayu90 : Merge branch 'hotfix/999' into develop
7f224cc 18-11-18 16:04 takayu90 : bugfix...
-       -       aaa/bbb/ccc/example
22      5       aaa/bbb/ccc/ddd/example.py
...
```
```bash
$ git gphone
*   cdb829d (HEAD -> develop, origin/develop) Merge branch 'feature/example' into develop
|\
| * f52b08a example commit
|/
*   bf0d6ae (origin/master) Merge branch 'hotfix/999' into develop
|\
| * 7f224cc bugfix...
...
```

引数にブランチ指定やファイル指定したり、ブランチ間の差分のコミットだけ表示したりもできます。

# diff - 差分
diffは差分を表示します。
主に以下のように使います。

```bash
# 最後のコミットから変更した差分を表示する
$ git diff aaa/bbb/ccc/example.js

# 上記と同様だが、ステージングした変更も表示する
$ git diff HEAD aaa/bbb/ccc/example.js

# 行末の空白などチェックしてくれる。
$ git diff --check
```

diffコマンドはスペース・タブ混在や行末の空白など警告してくれるので、コミット前に行うようにしましょう。

# まとめ
GUIツールの方が理解しやすいと思われる方もいらっしゃるかもしれませんが、筆者の感覚ではコマンドラインの方がシンプルでGitを理解しやすいのではないかなと思っています。
シェルの操作も覚えるきっかけになるのでおすすめです。