Windows で Git - 2017冬

# tl;dr

- 昔は Windows で Git を使うのは辛かったが、現在は悪くない
- Scoop で簡単に構築できる
- 操作は CLI, 閲覧は GUI クライアントで使い分けている
- GUI クライアントは、 VS Code がオススメ

# Git

言わずと知れた、バージョン管理システム。

# Windows と Git

そもそも Git は、 Unix/Linux 文化圏で生まれてきたもので、Windows 対応はされてはいるがイマイチな時期が長く続いた。

## イマイチだった点

- Git を導入するために、Git 以外の登場人物が多く辛い ( 特に新人 Windowser には
    - msys
    - Git Bash
    - ssh
- 情報が色々あって辛い
    - 3~4 年前までは、まだ Cygwin 派の記事もあった
    - Windows への導入の記事なのに、何となく Linux の知識ある前提だったり
- 鍵生成が辛い
    - putty 形式 ? OpenSSH 形式 ?
        - GUI クライアント使ってると、良くここで混乱した
- 文字化け辛い

## 最近の Windows × Git

- Git 導入
    - 取り敢えず **[Git for Windows](https://git-for-windows.github.io/)** で OK
- SSH、鍵生成
    - **[Win32-OpenSSH](https://github.com/PowerShell/Win32-OpenSSH)** で OK
- Git Bash
    - 上記2つができれば、**PowerShell** や **Command Prompt** でも十分 OK
- Windows での導入記事も増えている
- 文字化けは、まだまだ遭遇する…

全部ではないが、そこそこ改善してきている。

参考

[Windows環境でのgitまとめ(2016.8)](https://www.slideshare.net/ishisaka/windowsgit20168)

# 今、導入するなら

## Git

[別記事](https://qiita.com/kikuchi_kentaro/private/77793e4a21db6ffdb7cd) でも書いたが、Scoop 等を利用すれば簡単に導入できる。

```ps1
PS> scoop install git

PS> git --version
git version 2.15.0.windows.1
```

後は、`git config --global` で基本情報を設定して終わり。

```ps1
PS> git config --global user.name "名前"
PS> git config --global user.email "メールアドレス"

PS> git config --global core.autoCRLF false                    # 勝手に改行コード変えない
PS> git config --global core.excludesfile ~/.gitignore_global  # 共通無視設定
PS> git config --global core.pager "LESSCHARSET=utf-8 less"    # 文字化け対応

# winmerge を使う場合
PS> git config --global diff.diff winmerge
PS> git config --global difftool.winmerge.cmd "'C:/Program Files/WinMerge/WinMergeU.exe' -e `$LOCAL `$REMOTE"

# 以下、チームのルールに合わせて
PS> git config --global merge.ff false                         # mergeは --no-ff
PS> git config --global pull.rebase preserve                   # pull は --rebase
```

## OpenSSH

Git 使う上で欠かせない SSH クライアント。SSH key 生成ツールも同封。

```ps1
PS> scoop install openssh

PS> ssh -Version
OpenSSH_7.5p1, LibreSSL 2.5.3

PS> ssh-keygen
Generating public/private rsa key pair.
...
```

## Git 拡張

Scoop には、Git を拡張するツールや便利ツールも一応そろっている

```ps1
PS> scoop install git-lfs git-town gibo
```

各詳細は、以下を参照

- [Git LFS](https://git-lfs.github.com/)
    - [Git LFSの導入方法](https://qiita.com/takish/items/4b397caa5549a39a8194)
- [Git Town](https://github.com/Originate/git-town)
    - [Git Townが割と便利かもって話](https://qiita.com/knhr__/items/48d42ec3083f4a2d8cfd)
- [gibo](https://github.com/simonwhitaker/gibo)
    -  [気付いたら.gitignoreはgiboで自動生成する時代になっていた](https://qiita.com/tmknom/items/c4bcebe17d25381fa45d)


# GUI クライアントを使うべきか問題

自分の Git クライアント遍歴は、**SourceTree → GitKraken → CLI**。
GUI クライアントの良さも理解しつつ、しかしプログラマであればやはり CLI には慣れた方が良いと思う。

## CLI を薦める理由

- Qiita, StackOverflow 等ネット上の技術情報の多くが CLI 前提となっている
    - 『GUI ではどうやるか』と翻訳する必要がない
- Git はそもそも出来ることが多く、やりたい操作が GUI で見つけられない / そもそもできない
    - CLI に移行して**『こんなこと出来るんだ、Gitって』**と感動
        - `reflog` とか `rebase --abort` とか
- 分散バージョン管理システム自体の複雑さに起因する本質的な複雑さは、GUI にしたから分かりやすくなると言うもんでもない
    - とは言え、コマンド体系はもう少しなんとか…

## しかし、諦めきれない GUI への思い

とは言え **情報を見る** という点に関しては、明らかに GUI クライアントの方が優れている。

- Branch Tree View
    - ブランチの全体的な流れを掴む
- Diff
    - フォルダ・ファイルの Diff
    - コミット間・ブランチ間
- コミット検索

なので、今の所 **操作は CLI・閲覧は GUI** とユルく分けて運用している ( CQS 原則っぽく )

## CLI と併用する GUI クライアント

[GUI クライアント一覧](https://git-scm.com/download/gui/windows)

<font color="Silver">※ それ以外にも、[tig](https://github.com/jonas/tig) や [git-foresta](https://qiita.com/takaakikasai/items/fc684d95c9841069889b) 等のテキストベース GUI も検討したが、表示がずれたり Perl が上手く動かなかったりと、Windows ネイティブ対応の壁にぶつかり保留中。</font>

で、今一番気に入っていて使っているのが、上記リンク先にはない **VS Code** 

# Visual Studio Code

高機能なテキストエディタ。
[Visual Studio Code](https://www.microsoft.com/ja-jp/dev/products/code-vs.aspx)

- そこそこ軽量
- コマンドパレットがあるので、**コマンドを何となく覚えていると呼び出せる**
- CLI からは、`code .` で起動
    - CLI 連携でとても楽
- Terminal が統合されているので、Git コマンドもそのまま実行できる
- 日本語対応

VS Code は、初めから VCS を操作・状態表現する機能を持ってる。
[バージョン管理 | Visual Studio Code Docs](https://vscode-doc-jp.github.io/docs/userguide/versioncontrol.html)

- Add & Commit, Remote 操作, Branch 操作などの基本操作が可能
    -  [変更箇所単位での Add も可能](https://stackoverflow.com/questions/34730585/are-partial-git-commits-possible-in-vscode/47331858#47331858)
- ファイルツリーに `git status` の状態変化を示すマークが表示
    - エディタ領域にも、行単位の変更状態の目印がつく
- Diff 表示もあり
    - diff-highlight 的な局所的ハイライト
    - Split View
    - コードのシンタックスハイライト

以下の記事で丁寧に解説してくれているので、参考に
[Visual Studio Code の git 連携機能と git コマンドについて (2017/11/19)](https://qiita.com/satokaz/items/4660ce57ca8eb456a096)

ここまでは基本機能。
ここから、拡張を入れることで **情報を見る** という機能を強化していく。

## GitLens

様々な Git 情報を提供してくれる拡張。
[GitLens](https://github.com/eamodio/vscode-gitlens)

以下、良くお世話になっている機能をピックアップ

- 変更者は誰か確認
    - **`git blame`** 相当
    - エディタパネルに、行単位で author, commit message, date が表示
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/b90832b1-8648-a8d1-2c92-35f24f24ac09.png)

- コミット検索
    - **`git log --grep XXXXX`** 相当
    - コマンドパレットで、`Search Commits` を入力
        - `XXXX` で、commit message 検索
        ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/a9e37357-1f2e-ae51-e796-ca41a7deda2a.png)
        - `@XXXX` で、auther 検索
        ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/8976270d-0f63-f7fb-112e-befafb5f732b.png)
        - `:XXXX` で、file 名検索
        ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/4bfc7b5d-7619-1b79-6a0e-45a8d6da5ee0.png)
        - `~XXXX` で、file コンテンツを正規表現で検索 ( `git log -G` )
        - `=XXXX` で、file コンテンツを正規表現で検索 ( `git log -S --pickaxe-regex` )
            - 出現回数の変化を見るため、リファクタリングによる移動や Formatter によるフォーマット変換ではヒットしない
        

- ファイル履歴一覧
    - **`git log -p FFFF`** 相当
    - コマンドパレットで、`Show File History`
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/e402eec8-b0f8-ba39-696d-35f780a6f16b.png)
    - Gitlens パネルを File History View に切り替えて見ることも可能
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/44a8e512-3341-4134-afcd-0be9658e47b0.png)
- ファイルの変更確認
    - **`git diff XXXX YYYY -- FFFF`** 相当
    - コマンドパレットで、
        - `Compare File with Branch...`
        - `Compare File with Revision...`
    - 後述する、**Git History** の方が直感的
- 特定ブランチのコミット履歴
    - **`git cherry -v XXXX`** 相当
    - コマンドパレットで、`Show Branch History`
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/2e538c91-5e09-cd3c-6fc5-29c78d2bd877.png)
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/eb0344cc-6f49-e476-b9ce-3e96a590a054.png)
    - カレントブランチなら、`Show Current Branch History`

## Git History

Git の GUI クライアントと言えば、やっぱり Branch Tree View が無いと
[Git History](https://github.com/DonJayamanne/gitHistoryVSCode)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/7ab9cce0-212a-6752-235a-eb0b9d72d059.png)

- 全体的なブランチの流れを掴む
- コミットの変更をサクッと見るのにはちょうどいい
- 離れたコミット間の差分は、**Gitlens** よりも直感的

## Git Tree Compare

あるブランチを Base に指定すると、現ブランチとの**分岐点からの差分比較**をしてくれる拡張。
[Git Tree Compare](https://github.com/letmaik/vscode-git-tree-compare)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20198/c53528cf-b281-b587-3e4e-25966ae31a6e.png)
※ `master` をベースにした、カレントブランチとの差分

- 変更ファイルを一覧表示してくれる。しかも自動更新
    - **`git diff --name-only XXXX...current`** 相当
        - 内部的には、`git diff-index --no-renames --name-status $(git merge-base XXXX current)` をしている ( 違いは分からない … )
    - ファイルクリックで Diff 表示
- e.g. develop ブランチを Base に指定し、 future ブランチでの変更差分を見たい
    - Github の Pull Request 時の差分と同じ

# まとめ

そこそこ満足してる。
けど、やっぱりもっと GUI GUI していて直感的なやつが欲しい。
[Fork](https://git-fork.com/) が凄く良さそうなので、今後の Windows 対応に期待。

[Github 編に続く]()

# おまけ

### git config 切り替え

例えば、Github と 社内 Gitlab で SSH key を分ける場合、`~/.ssh/config` を使うと思うが、ユーザ名やメールアドレスも変えたい場合、困るケースがある。

そんな時は、**includeIf** を使うと便利。

● `C:/ghq` 以下に Github プロジェクトを集中させている場合

```:~/.gitconfig_github
[user]
  name = github_user
  email = github_user@example.com
```

```:~/.gitconfig
..

[includeIf "gitdir:C:/ghq/"]
  path = ~/.gitconfig_github
```

こんな感じに、個別に設定ファイルを作成し、`includeIf` でフォルダパスが条件にヒットした場合のみ読み込むということができる。

詳しくは、以下の記事がとても良くまとまっているので参考に
[gitアカウントを作業フォルダによって自動で変更できるようにする](https://ajike.github.io/Git%E3%82%A2%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88%E3%82%92%E4%BD%9C%E6%A5%AD%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E5%A4%89%E6%9B%B4%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B/)