gitの差分比較をWinMergeでしたい！(Bash on Ubuntu on Windows編)

(2018/06/17)
「Windows 10 April 2018 Update」の Ubuntu 18.04 では以下を参照して下さい。
[WSL(Ubuntu 18.04)環境のgitでWinMergeを使う方法](https://qiita.com/forest1/items/334b5d756b5696c63331)

---
Bash on Ubuntu on Windows (WSL)のgit環境でもWinMergeを使えるようにしてみました。
なかなか同じ例が見つからなかったので、シェル周りが悪戦苦闘で、大変でした。。

# 作業パス変更
## リポジトリを /mnt/c 以下に置く
/home/username 以下はWindowsアプリから扱えないので、/mnt/c/Users/username 以下に移動します。

わざわざ cd /mnt/c/Users/username とするのも面倒なので、シンボリックリンクを作成しておきます。

```
$ cd ~
$ ln -s "/mnt/c/Users/username" win
$ cd win; mkdir gitwork; cd gitwork
$ git init
$ git ...
```

## テンポラリフォルダのパスを変更する
gitのdifftool(WinMerge連携の仕組み)は、一旦テンポラリフォルダにチェックアウトしてから、そのパスをツール(WinMerge)に渡すというものです。

Bash on Ubuntu on Windows環境下では標準で /tmp となっていますので、Windowsアプリから見えるパスに変更してやります。

~/.bashrc に以下を追記します。

```
function winpath()
{
  if [ -p /dev/stdin ]; then
    input_path=$(cat -)
  else
    input_path=$(echo $@)
  fi
  /bin/readlink -f $input_path | sed -e "s|^\(/mnt/\([a-z]\)\)\(.*\)|\U\2:\E\3|" -e "s|/|\\\\|g"
}

function linuxpath()
{
  if [ -p /dev/stdin ]; then
    input_path=$(cat -)
  else
    input_path=$(echo $@)
  fi

  echo $input_path | sed -e "s|\\\\|/|g" -e "s|^\([A-Za-z]\)\:/\(.*\)|/mnt/\L\1\E/\2|"
}

export TMPDIR=`echo "$(/mnt/c/Windows/System32/cmd.exe /C echo %TEMP%)" | tr -d "\r" | linuxpath`
```

参考資料)
[aseering/winpath,sh](https://gist.github.com/aseering/a06219e74c7f96ccea5ec65d5b2483b5)

使い方は。
winpathが、/mnt/c/から始まる Linuxパスを Windows形式のパス(C:\)に変換。

```
echo /mnt/c/Users/username | winpath
or
winpath /mnt/c/Users/username
```

linuxpathが、Windows形式パス(C:\\)をLinuxパス(/mnt/c)に変換。

```
echo 'C:\Users\username' | linuxpath
or
linuxpath "C:\Users\username"
```

なお、export TMPDIR=... を実行すると、「現在の作業ディレクトリを変換できません。C:\Users\username を使用します」というメッセージが出てきます。
これはカレントディレクト(/home/username)をWindowsパスに変換しようとしたけど出来なかったというメッセージです。ここでは問題無いのでスルーします。)


# Gitに WinMerge を設定する
~/gitconfig に以下を記載します。

```
[diff]
    tool = WinMerge
[difftool]
    prompt = false
[difftool "WinMerge"]
    path = '/mnt/c/Program Files/WinMerge/WinMergeU.exe'
    cmd = \"/mnt/c/Program Files/WinMerge/WinMergeU.exe\" -e -r -u -x -wl -wr -dl \"a/$MERGED\" -dr \"b/$MERGED\" \"`echo ${LOCAL%/} | sed -e 's|^\\(/mnt/\\([a-z]\\)\\)\\(.*\\)|\\U\\2:\\E\\3|' -e 's|/|\\\\\\\\|g'`\" \"`echo ${REMOTE%/} | sed -e 's|^\\(/mnt/\\([a-z]\\)\\)\\(.*\\)|\\U\\2:\\E\\3|' -e 's|/|\\\\\\\\|g'`\"
    trustExitCode = false
[merge]
    tool = WinMerge
[mergetool]
    prompt = false
    keepBackup = false
[mergetool "WinMerge"]
    cmd = \"/mnt/c/Program Files/WinMerge/WinMergeU.exe\" -e -u \"`echo ${MERGED%/} | sed -e 's|^\\(/mnt/\\([a-z]\\)\\)\\(.*\\)|\\U\\2:\\E\\3|' -e 's|/|\\\\\\\\|g'`\"
    trustExitCode = false
[alias]
    windiff = difftool -y -d --no-symlinks -t WinMerge
    winmerge = mergetool -y -t WinMerge
```

参考資料)
[Windows の各種 Git 環境で diff / merge に WinMerge を使うための設定](http://qiita.com/amano41/items/7c4be8d44cbff6417f7e#_reference-40532310bba4301e06c5)


これで設定は完了です。

# 使い方

- 比較

git diff と同じです。

```
git windiff [比較元] [比較先]
```

- マージ

git mergeとかpull, rebase, cherry-pick などでコンフリクトしたら、

```
git winmerge
```

と叩いて下さい。
例えば、git merge origin/develop とやってコンフリクトした場合、
WinMergeの左側ペインがorigin/develop、右側が自ブランチとなっています。
右側にマージ編集して保存＆WinMergeを閉じるとファイルがステージングされた状態になります。

git windiff --cached とすると、マージ後の状態が見れます。

あとはコミットするだけです。