ポータブル環境でVSCodeからGitHubプライベートリポジトリを使う

# ポータブル環境でVSCodeからGitHubプライベートリポジトリを使う

**[【ぜんぶポータブル】ポータル](https://qiita.com/jtFuruhata/items/f9788da8e480c646a2a9)**

**最終更新:2019年3月8日**

このドキュメントは、ワクワクしながらVSCodeからGitHubのプライベートリポジトリを使おうとして、

![2019-02-18-10-35-43.png](https://qiita-image-store.s3.amazonaws.com/0/151581/37510bef-14dd-9bfa-48e0-57d0670e9625.png "Git: remote: Repository not found.")

とか、

![2019-02-18-10-33-05.png](https://qiita-image-store.s3.amazonaws.com/0/151581/3e6f0710-bb13-9758-fced-df268dd8569d.png "Git: git@github.com: Permission denied (publickey).")

の悪夢に悩まされている方向けです。それズバリ認証失敗です。

スマートな解決策が他にあるかもしれませんが、僕が色々試したところでは、どうしても/dev/tty問題が解決できず、VSCodeのパスフレーズ入力ダイアログを回避してssh-agentに認証を任せるしかありませんでした。ここではその手法を説明します。

## 構築に使用した環境

- Windows10 Version 1803
- Visual Studio Code 1.31.0 zip版
- (Portable)Git for Windows 2.20.1
- ポータブル環境ではないVSCodeとGitもインストールされている（がこちらは使わない）
- ポータブル環境は以下の様にVSCodeとPortableGitが展開されている

```
[jtHiuPortable]
├───[apps]
│   └───[win]
│       ├───[VSCode]
│       ├───[PortableGit]
│       └───Code.cmd
├───[files]
└───VSCode_Win.lnk
```

- 自前で用意した2つのファイルのうち、`Code.cmd`は以下の様な内容で、`VSCode_Win.lnk`は`Code.cmd`への[トリックショートカット](https://qiita.com/jtFuruhata/items/58b5631ec27038aa1312)である[^cmdファイル]

[^cmdファイル]: *.cmdファイルは「Windowsコマンドスクリプト」、*.bat上位互換のいわゆるバッチファイルです。*.batだと遅延展開など現代風のバッチが書けず、*.ps1だと実行に管理者権限が必要な場合が多いので、ここでは*.cmdを使用します。

```:コマンドプロンプト
> echo start %~dp0VSCode\Code.exe > Code.cmd
```

ここまでで「えぇっと…」と思った方は、このページではなく[ステップバイステップ](https://qiita.com/jtFuruhata/items/f9788da8e480c646a2a9)の方で進めてください。

### 確認済みの事項

- ○ Windows7での動作を確認しました。
- ○ ネットワークドライブ（情報大のZ:ドライブ）での動作を確認しました。
- ○ OneDrive上での動作を確認しました。
- × パス中に日本語フォルダ名を含むとダメです。
    - OneDrive母艦方式で`C:\Users\太郎>`とかいうのが一番厄介
    - ↑「([Windows10のユーザーフォルダ名変更](https://qiita.com/aaaKUKIaaa/items/83d6234b69b0d958d3f1)」の**手順2**がオススメです。
- × UNCパスもダメです。
    - Windowsエクスプローラーのホーム→新規→ショートカット→「ドライブとしてマップ」からドライブレターを割り当ててください。
- × Mac上VMwareのvmware-host経由では、ドライブとしてマップでもダメでした。
    - デバイスごとWindowsに接続している場合は大丈夫です。OneDriveもOK。ただし、なぜかVSCode起動用バッチのコマンドプロンプトが終了しませんので、気にしないのが吉です。

## ポータブル環境用Gitの使用を明示する
デフォルトでは当然、マシンにインストールされているGitを使いに行こうとしますが、まずはこれをポータブル環境へ引き込むためにパスなどの環境変数を設定するバッチファイルを作成します。

```:コマンドプロンプト
D:\jtHiuPortable> touch apps\win\setPath.cmd
```

```setPath.cmd
@echo off
if Defined AppsWinRoot GoTo PostPathSettings
echo Portable Console is preparing environment variables.
set NOW_CD=%cd%
cd /D %~dp0..\..
set HOME=%cd%
cd /D %NOW_CD%
set AppsWinRoot=%HOME%\apps\win
set GitD=%AppsWinRoot%\PortableGit
set PATH=%GitD%\cmd;%GitD%;%GitD%\usr\bin;%path%
:PostPathSettings
echo Portable home has located in %HOME%
echo Portable applications have located in %AppsWinRoot%
```

要点解説：

- **2行目** … 多重起動によるPATH登録の無限増殖を防いでいます。
- **%~dp0** … 「動作中のスクリプトファイルがあるパス」です。
- **環境変数HOMEの設定** … sshなどMSYS2(MinGW64)なコマンドは環境変数HOMEをホームディレクトリとして使用します。環境変数に相対パスの部分を残したくなかったので、ちょっと面倒な手順を踏んで設定しています。
- **PATHへの追加項目**
    - `%GitD%\cmd` … git起動用
    - `%GitD%` … git-bash起動用
    - `%GitD%\usr\bin` … MSYS2(MinGW64)各種コマンド向け

これを、きちんとポータブル環境で動作しているか確認するため、あえて標準のホームから叩いてみます。sshはもちろん接続にコケますが、ポータブル環境のホームに`.ssh`フォルダが自動的に作成されたことを確認してください。

```:コマンドプロンプト
Microsoft Windows [Version 10.0.17134.590]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\MyName>D:\jtHiuPortable\apps\win\setPath.cmd
Portable Console is preparing environment variables.
Portable home has located in D:\jtHiuPortable
Portable applications have located in D:\jtHiuPortable\apps\win

C:\Users\MyName>git --version
git version 2.20.1.windows.1

C:\Users\MyName>git-bash
（git-bashのウィンドウが開く）

C:\Users\Nyname>ssh -T git@github.com
The authenticity of host 'github.com (192.30.255.113)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
Are you sure you want to continue connecting (yes/no)?
（とりあえず空Enter）
Host key verification failed.
```

```bash:MINGW64：/c/Users/MyName
MyName@MyWin MINGW64 /c/Users/MyName
$ ls ~
apps/ files/ VSCode_Win.lnk
```

これで、gitやsshが起動することと、git-bash上でホームディレクトリがきちんとポータブル環境のフォルダになっていることを確認できました。

`apps\win`にあるVSCode起動用バッチファイルも、これを経由するようにします。

```Code.cmd
@echo off
call %~dp0setPath.cmd
start %~dp0VSCode\Code.exe
```

## VSCodeのGit自動検索を回避する
VSCodeは起動時に、標準的なGit for Windowsのインストール場所を巡回して探してくるという**ポータブル環境にとっては大変余計なこと**をしてくれます。そんな訳で仕方なく`settings.json`の`git.path`にフルパス書くんですが汎用性が低い。なんで、これでいいです。てか、こう書いてください。

```json:settings.json
{
    "git.path": "git"
}
```

セキュリティリスクは判るけどこれをデフォルトにしてくれよ…とも思うんですが…　こうするとパスの通ったGit環境を使ってくれます。もちろん既に色々設定している方は、この一行（と行末にコンマも付けて）追加してください。ちなみに`settings.json`は`Ctrl+Shift+P`でコマンドパレットを開いて、`open settings (j`ぐらいまで打てば開けます。

## ポータブル環境向けのSSHキーを作成し、GitHubに登録する
既にSSHキーをお持ちの方も多いとは思いますが、ポータブルデバイス紛失のリスクを考えると、大事な秘密鍵を持ち歩きたくはありませんので、ポータブル用のキーペアを新たに作成する方が安心です。フォーマットは[GitHubの流儀](https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/)に従って作成します。

詳細は「[SSHキーを作成してGitHubに登録する](https://qiita.com/jtFuruhata/items/d9d3a8edf1ecfe1c1d23)」にまとめましたので、やり方がピンとこない方はご参考に。

ここまでのフォルダ構造を確認すると以下の様な感じです。

```
[jtHiuPortable]
├───[.ssh]
│ ├───known_hosts
│ ├───rsa_GitHub
│ └───rsa_GitHub.pub
├───[apps]
│ └───[win]
│ ├───[VSCode]
│ ├───[PortableGit]
│ ├───Code.cmd
│ └───setPath.cmd
├───[files]
├───.bash_history //もちろんこれはなくてもいい
├───.gitconfig
└───VSCode_Win.lnk
```

## ssh-agentを起動する
これでOKなはずなんですけどどうにもパスワードを聞いてくれない。そこで`ssh -v`とか色々とデバッグログを見ていると、きちんとポータブル環境のファイルは見に行ってるんだけど、パスフレーズの入力で`/dev/tty`がねぇぞってことでコケる。もちろんコマンドで叩けばちゃんとcloneできる。ってなわけで、[GCM](https://github.com/Microsoft/Git-Credential-Manager-for-Windows)とか色々物色して試したんですけどダメで、普通に(?)ssh-agentを使うことにしました。

まず、`start-ssh-agent`を使うのですがバッチファイルから呼び出すと`cmd`を起動してダンマリするので塩梅が悪いため、ファイルをコピーして、

```:コマンドプロンプト
> copy %GitD%\cmd\start-ssh-agent.cmd %AppsWinRoot%\summon-ssh-agent.cmd
    1個のファイルをコピーしました。
```

下から2行目の`cmd`起動部をREMっちゃいます。

```:summon-ssh-agent.cmd

    ~ 省略 ~

@IF NOT ERRORLEVEL 1 @(
REM    @CALL cmd %*
)
```

そして、パス設定のバッチファイル最後で召喚します。一応全掲。

```setPath.cmd
@echo off
if Defined AppsWinRoot GoTo PostPathSettings
echo Portable Console is preparing environment variables.
set NOW_CD=%cd%
cd /D %~dp0..\..
set HOME=%cd%
cd /D %NOW_CD%
set AppsWinRoot=%HOME%\apps\win
set GitD=%AppsWinRoot%\PortableGit
set PATH=%GitD%\cmd;%GitD%;%GitD%\usr\bin;%path%
:PostPathSettings
echo Portable home has located in %HOME%
echo Portable applications have located in %AppsWinRoot%
call %~dp0summon-ssh-agent
```

VSCodeを黙らせることが目的ですので、VSCode起動バッチの方に使用するキーを追加します。ちょっとだけ多重起動対策してます。4行目の`ssh-add`以降は、`.ssh`の`config`の`IdentityFile`に書いたものをコピペしてください。ハードコードは美しくないんですが、この辺は後々構築が進んだら環境変数を使うことにします。

```Code.cmd
@echo off
call %~dp0setPath.cmd
ssh-add -l
if ErrorLevel 1 ssh-add ~/.ssh/rsa_GitHub
start %~dp0VSCode\Code.exe
```

あとは、VSCodeをバッチ経由で起動しようとすると、ssh-agentがいない場合は召喚し、パスフレーズが入力されていなければそれを承認してからVSCodeが起動します。

```:バッチファイル動作中
Portable Console is preparing environment variables.
Portable home has located in D:\jtHiuPortable
Portable applications have located in D:\jtHiuPortable\apps\win
Removing old ssh-agent sockets
Starting ssh-agent:  done

The agent has no identities.
Enter passphrase for /d/jtHiuPortable/.ssh/rsa_GitHub:
（パスフレーズを入力してEnterキー）
```

## ssh-agentを停止する

通常の使用であればVSCodeを開き直してもパスフレーズを再入力する必要がないので便利ですが、共有マシンなどでログインしっぱなしなのは問題がある場合も多いですし、**何よりssh-agentの召喚中は「ハードウェアを安全に取り外してデバイスを取り出す」ができない**ので、召還するスクリプト`recall-ssh-agent.cmd`を`apps\win`に用意して、ここに飛ぶ[トリックショートカット](https://qiita.com/jtFuruhata/items/58b5631ec27038aa1312)`RecallAgent_Win.lnk`もポータブル環境フォルダに作成、必要に応じてダブルクリックして自動認証を終了させられるようにします。

```recall-ssh-agent.cmd
@SETLOCAL EnableDelayedExpansion
@FOR /f "tokens=1-2" %%a IN ('tasklist /fi "imagename eq ssh-agent.exe"') DO @(
    @ECHO %%b | @FINDSTR /r /c:"[0-9][0-9]*" > NUL
    @IF "!ERRORLEVEL!" == "0" @(
        @SET SSH_AGENT_PID=%%b
        %~dp0PortableGit\usr\bin\ssh-agent -k
    )
)
```

要点解説：基本的には`start-ssh-agent.cmd`からPID取得部を持ってきています。

- **1行目** … 遅延展開の使用を宣言します。
- **2-3行目** … tasklistコマンドをforから用いて、起動中のssh-agentを検索し、PIDの部分を取得します。
- **4-6行目** … きちんと取得できたら、ssh-agentが参照する環境変数に代入し、さよならします。

## オプション：VSCodeの英語モード起動をなんとかする
インストール直後はしょうがない。ただ、ポータブル環境デバイスを他のマシンで利用する時（恐らくドライブレターが変更された時）、初回のみ英語モードで起動してしまいます。`code.cmd --locale ja`でもダメです。恐らく、起動時に拡張機能（各国語対応も拡張機能）を遅延読み込みするため、環境が変わってElectronが混乱している間に日本語拡張が読み込まれないままワークベンチが表示されてしまうからでは、と推測していますが、初回時（パスフレーズを入力する時）には自動的にVSCodeを再起動するように変更した`Code.cmd`を示します。**気にならない方はウザいだけですので変更しなくて結構です**。

```Code.cmd
@REM WARNING: This Windows command script is tainted with BASH commands
@echo off
call %~dp0setPath.cmd
ssh-add -l
if ErrorLevel 1 (
    setlocal EnableDelayedExpansion
    ssh-add ~/.ssh/rsa_GitHub
    echo ------------------------------------------------------------
    echo ** WARNING **
    echo Visual Studio Code will *RESTART* after boot. Please wait...
    echo ------------------------------------------------------------
    start %~dp0VSCode\Code.exe
  :loop
    sleep 1
    set COUNT=0
    for /f "skip=3 tokens=1" %%a in ('tasklist /fi "imagename eq code.exe"') do (
        set /a COUNT+=1
    )
    if "!COUNT!" LSS "6" goto :loop
    echo Visual Studio Code is restarting now. Please wait...
    for /f "tokens=3" %%a in ('%~dp0VSCode\bin\code.cmd --status ^| grep code') do (
        taskkill /PID %%a > nul 2>&1
    )
    endlocal
)
start %~dp0VSCode\Code.exe
```

要点解説：**割愛**
これが読めるようになると、大抵のバッチファイルは書けるはず。Electronがウィンドウ作るんで/minも>nulも効かないのがお騒がせになって残念。や、VSCodeのバグ取れるといいっすね。

## クローンする
はいこれで本当にOK。早速git cloneしましょう。プライベートリポジトリの初期化はGitHubサイトの方で済ませておいてください。
![2019-02-18-15-04-43.png](https://qiita-image-store.s3.amazonaws.com/0/151581/d7020fd6-ca33-d66f-3b6c-b42c8ee12f40.png)
リポジトリを開いたら右側の`Clone or download`ボタンをクリック、そのダイアログが`Clone with SSH`になっていることを確認、もしも`Clone with HTTPS`となっていたら、その横（画像ではUse HTTPSとなっている場所）に`Use SSH`リンクがあるのでそれをクリックして切替、その下のアドレスがかかれた右側にある、クリップボードに左矢印ボタンを押してアドレスをコピーします。
![2019-02-18-15-02-49.png](https://qiita-image-store.s3.amazonaws.com/0/151581/a8cb106c-d837-2659-031f-e6dd99709b3e.png)
`Ctrl+Shift+P`でコマンドパレットを開き、`git clone`ぐらいに入力すると`Git: クローン`が出るのでそれを選択、
![2019-02-18-15-09-20.png](https://qiita-image-store.s3.amazonaws.com/0/151581/8d05eaf4-14b2-403a-80b4-6eb3377b3b2c.png)
リポジトリのURLを聞かれるので、入力欄をクリックして`Ctrl+V`で貼り付け、
![2019-02-18-15-12-54.png](https://qiita-image-store.s3.amazonaws.com/0/151581/4736842d-3f7d-3cdb-9a50-fe820dc10944.png)
`Enter`キーを押すとダイアログが出るので、ポータブル環境の`files`フォルダを選択して`リポジトリの場所を選択`ボタンを押します。すると`files`の下にリポジトリと同名のフォルダを作成して持ってきます。git initもいらないです。

下の奴が出てもこれはエラーじゃないんでビビらなくてOKです。
![2019-02-18-15-15-39.png](https://qiita-image-store.s3.amazonaws.com/0/151581/2d372bf4-ced0-d553-cf31-cee793083469.png)

ほら、ようやくこのダイアログに巡り合えました。
![2019-02-18-16-32-19.png](https://qiita-image-store.s3.amazonaws.com/0/151581/29859e09-d5fd-f14b-a163-2cd9e08d0345.png)

手順通りにやると、最終的にはこの様な配置になります。もちろん`files`以下はクローンしたリポジトリによって様々です。

```
[jtHiuPortable]
├───[.ssh]
│       ├───known_hosts
│       ├───rsa_GitHub
│       └───rsa_GitHub.pub
├───[apps]
│   └───[win]
│       ├───[VSCode]
│       ├───[PortableGit]
│       ├───Code.cmd
│       ├───recall-ssh-agent.cmd
│       ├───setPath.cmd
│       └───summon-ssh-agent.cmd
├───[files]
│   └───[sandbox]
│       ├───[.git]
│       ├───.gitignore
│       ├───LICENSE
│       └───README.md
├───.bash_history
├───.gitconfig
├───VSCode_Win.lnk
└───RecallAgent_Win.lnk
```

以上です。では、Happy Coding!