Herokuにgit pushしても反応がない（急にgit pushできなくなった）場合の対処方法

## はじめに
昔からHerokuで運用しているRailsアプリをHerokuにgit pushしようとしたら、反応がなくて困りました。

```
$ git push heroku-staging master
（反応なし）
```

しばらく待つと以下のようなエラーメッセージが出ました。

```
ssh: connect to host heroku.com port 22: Operation timed out
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```

今まではこれでデプロイできてたのに、いったいどうして？？と思っていろいろ調べてみました。

## どうやらsshでgit pushできなくなったらしい

Herokuのヘルプページによると、sshを使ったgit pushはサポートされなくなったようです。

https://devcenter.heroku.com/changelog-items/2301

> As Heroku continues to make architecture upgrades to improve performance, the SSH Git Transport feature is deprecated as of November 30, 2021.
>
> The only Git transport configured by the Heroku CLI is HTTP. You must make all git pushes using the HTTP Git deployment method starting December 1, 2021.

## Heroku CLIでHTTP接続する設定を追加する

現在はHTTPを使ったデプロイしかできなくなっているので、下記ヘルプページにあるとおり、Heroku CLIを使ってHTTP接続する設定を追加する必要があるとのこと。

https://devcenter.heroku.com/articles/git#for-an-existing-heroku-app

というわけで、以下のようなコマンドを実行しました。

```
# -aはHeroku上のアプリ名、-rはリモートリポジトリ名（任意）
heroku git:remote -a my-awesome-app -r heroku-staging-http
```

よし、これでOKなはず。というわけで、git pushを実行してみます。

```
git push heroku-staging-http master
```

するとユーザー名とパスワードを聞かれるので、Herokuログインで使用しているユーザー名（メールアドレス）とパスワードを入力します。

```
Username for 'https://git.heroku.com': myname@example.com
Password for 'https://myname@example.com@git.heroku.com': 
```

人によってはこれでデプロイに成功するかもしれませんが、僕の場合は以下のようなエラーが出てまたデプロイに失敗しました。

```
remote: !	WARNING:
remote: !	Do not authenticate with username and password using git.
remote: !	Run `heroku login` to update your credentials, then retry the git command.
remote: !	See documentation for details: https://devcenter.heroku.com/articles/git#http-git-authentication
fatal: Authentication failed for 'https://git.heroku.com/my-awesome-app.git/'
```

## 一般的な解決方法：heroku loginを使ってログインする

`heroku login`コマンドを実行してログインすると、`~/.netrc`に認証情報が書き込まれるので、それ以降はふつうにgit pushできるようになるはずです。

この情報は @zunda さんに教えていただきました（どうもありがとうございます！）。

https://twitter.com/zundan/status/1553817415980486656

ただし、僕のマシンではセキュリティ対策としてGPGToolsが導入されていたため、以下の方法で解決しました。

## GPGTools(GPG Suite)を使っている場合

GPGToolsを使っている場合は以下の手順で対応します。

### Step 1. API tokenを使ってログインするように設定する

まず、API tokenを使ってログインできるようにします。

参考情報

- https://devcenter.heroku.com/articles/git#http-git-authentication
- https://devcenter.heroku.com/articles/authentication

Heroku CLIを使ってAPI tokenを生成しましょう。

```
$ heroku auth:token
 ›   Warning: token will expire 08/30/2022
 ›   Use heroku authorizations:create to generate a long-term token
8aeec5f2-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

が、警告メッセージに「トークンの有効期限は2022年8月30日」と書いてあります。1ヶ月しか使えないのはちょっと短すぎますね。`heroku authorizations:create`というコマンドを使えば有効期限のないトークンが作れるようです（[参考](https://devcenter.heroku.com/ja/articles/platform-api-quickstart)）。

というわけで`heroku authorizations:create`を実行してみました。

```
$ heroku authorizations:create
Creating OAuth Authorization... done
Client:      <none>
ID:          3d869571-xxxx-xxxx-xxxxxxxxxxxxxxxxx
Description: Long-lived user authorization
Scope:       global
Token:       5017ef9c-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Updated at:  Sun Jul 31 2022 13:55:21 GMT+0900 (Japan Standard Time) (less than a minute ago)
```

続いて`~/.netrc`を開き、上で取得したトークンをパスワード代わりに書き込んで保存します。

```~/.netrc
machine api.heroku.com
  login myname@example.com
  password 5017ef9c-xxxx-xxxx-xxxx-xxxxxxxxxxxx
machine git.heroku.com
  login myname@example.com
  password 5017ef9c-xxxx-xxxx-xxxx-xxxxxxxxxxxx
```

いったんこれでデプロイできることを確認します。

```
$ git push heroku-staging-http master
Enumerating objects: 55, done.
Counting objects: 100% (43/43), done.
Delta compression using up to 8 threads
Compressing objects: 100% (23/23), done.
Writing objects: 100% (23/23), 6.71 KiB | 3.35 MiB/s, done.
Total 23 (delta 13), reused 0 (delta 0), pack-reused 0
remote: Compressing source files... done.
remote: Building source:
（以下略）
```

### Step 2. ~/.netrcを暗号化する

続いて、以下のコマンドを実行して~/.netrcを暗号化します。

```
cd ~
gpg -e -r myname@example.com ~/.netrc
chmod 600 .netrc.gpg 

# 暗号化されていて読めないことを確認
cat .netrc.gpg 

# 元のテキストが表示されることを確認
gpg -d .netrc.gpg 

# 平文のファイルは危険なので削除
rm ~/.netrc
```

### Step 3. gitのcredential helperをセットアップする

Macの場合、以下の2つのファイルが存在することを確認します。

```
$ ls /Library/Developer/CommandLineTools/usr/share/git-core/perl/Git.pm
/Library/Developer/CommandLineTools/usr/share/git-core/perl/Git.pm

$ ls /opt/homebrew/share/git-core/contrib/credential/netrc/git-credential-netrc.perl
/opt/homebrew/share/git-core/contrib/credential/netrc/git-credential-netrc.perl
```

環境変数としてPERLLIBを追加します。

```~/.zshrc
export PERLLIB="/Library/Developer/CommandLineTools/usr/share/git-core/perl"
```

`~/.gitconfig`を開き、以下の設定を追記します。

```~/.gitconfig
# 既存の設定は省略...
[credential "https://git.heroku.com"]
    helper = "/opt/homebrew/share/git-core/contrib/credential/netrc/git-credential-netrc.perl --gpg gpg -f $HOME/.netrc.gpg get"
```

### Step 4. 動作確認

設定が終わったら再度デプロイが成功する（エラーが出ない）ことを確認します。
（gpgが使用されていることを示すメッセージも表示されます）

```
$ cd ~/path/to/my-awesome-app
$ git push heroku-staging-http master
gpg: encrypted with 4096-bit RSA key, ...略
      "Scott Tiger <myname@example.com>"
Everything up-to-date
```

herokuコマンドも実行できることを確認しておきましょう。

```
$ heroku list
# ...Heroku上のアプリ一覧が表示される
```

### 参考：credentialを削除する場合

Macの場合、credential情報はKeychainに保存されるはずです。

![gpg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/f8201057-015e-96ad-fbfb-be3a5d83b662.png)

この情報はKeychain Accessからは削除できません。
削除する場合は以下のコマンドを実行します。

```
git credential-osxkeychain erase
```

このコマンドを実行すると、入力待ち状態になるので、以下の情報を入力します。

```
host=git.heroku.com
protocol=https
```

最後にリターンキーを押すと、Keychainからcredential情報が削除されます。

## GitHub統合するのもあり

git pushでデプロイするのではなく、HerokuとGitHubを統合し、GitHubにpushしたら自動デプロイされるようにする方法もあります。
その場合は「Step 3. gitのcredential helperをセットアップする」は省略可能です。

https://devcenter.heroku.com/ja/articles/github-integration

## まとめ

対応方法は以上です。

僕と同じように「なんで今までgit pushできてたのに急にできなくなったの！？」という人はこの記事を参考にしてみてください。

### 参考文献
- [How to setup git\-credential\-netrc with encrypted \.netrc credentials](https://gist.github.com/jiajie-chen/c043e484662c40c1770c440558b54919)