devcontainer内でgitを使いたい

# 背景

devcontainer内でgithubにpushしたい。できないと開発中煩わしい。

pushはsshキーを使う。

OSはwindows11。

# 解決法

### Step1(devcontainer内でgitコマンドを使えるまで)

devcontainerの使用イメージにデフォでgitがインストールされているイメージを使用するか、dockerfileでRUNを使用してgitをインストールする。

`mcr.microsoft.com/devcontainers/python:1-3.12-bullseye`はpythonを使用したいかつ、デフォでgitが入っているので使用。

```docker
FROM mcr.microsoft.com/devcontainers/python:1-3.12-bullseye
```

これで、gitコマンドは使えるはず。

### Step2(デフォルトブランチをmainにする)

`git init`コマンドを打つと

```docker
vscode ➜ /app $ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint:   git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint:   git branch -m <name>
```

`git config --global init.defaultBranch main` を設定すればOKだが、毎度新しいdevcontainerを立ち上げるたびに打つのは面倒なので

`.devcontainer`に以下を追加する。

```docker
"postCreateCommand": "git config --global init.defaultBranch main"
```

docker-composeを`.devcontainer`で使用している場合はgitを使いたいサービスにcommandを追加。

```docker
    command: /bin/bash -c "git config --global init.defaultBranch main && tail -f /dev/null"
```

- `git config --global init.defaultBranch main`：デフォルトのブランチ名を `main` に設定。
- `tail -f /dev/null`：コンテナが終了しないようにするためのコマンド。

### Step3(devcontainer内のディレクトリを安全なディレクトリとしてgitに認識させる)

`git add` コマンドを打つと

```docker
vscode ➜ /app $ git add .
fatal: detected dubious ownership in repository at '/app'
To add an exception for this directory, call:

        git config --global --add safe.directory /app
```

このエラーは、gitがリポジトリの所有者を確認できないために発生します。

これは、特にdockerやdevcontainerのような環境でよく見られます。Gitはリポジトリのセキュリティを保つために、所有者が異なるディレクトリを「疑わしい」とみなします。

この時、.devcontainerに以下を追加。

```docker
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}"
```

docker-composeを`.devcontainer`で使用している場合はgitを使いたいサービスにcommandを追加。

```docker
    command: /bin/bash -c "git config --global --add safe.directory <ディレクトリ名> && tail -f /dev/null"
```

### Step4(devcontainer内でsshキーを使用してgithubにアクセス)

sshキーはローカルである前提。ない人は公式をチェック。

https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

devcontainer内でpushしようとすると下記エラー。

```docker
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
```

サーバーが接続を却下されました。sshキーを持っていないようです。

https://code.visualstudio.com/remote/advancedcontainers/sharing-git-credentials

公式には

> There are some cases when you may be cloning your repository using SSH keys instead of a credential helper. To enable this scenario, the extension will automatically forward your **local [SSH agent](https://www.ssh.com/ssh/agent) if one is running**.
> 

要は、**ローカルでssh-agentが動いていたらdevcontainerでもsshキーが使えますよ**、ということらしい。

ssh-agentとはsshプロトコルを使用するための認証情報（SSHキーのパスフレーズなど）を管理するデーモンです。
主な役割は、ユーザーがsshキーを使ってリモートサーバーにログインする際に、**キーのパスフレーズを一度だけ入力することで、その後の認証を自動的に行う**ことです。

便利です。しかし注意としてターミナルを閉じると、ssh-agentも終了するため、次回ターミナルを開いても以前のセッションで追加した鍵のパスフレーズは保持されません。

私はssh-agentに追加していなかったので、そこからやりました。

windowsでssh-agentが動いていることを確認したら、ssh-agentにsshキーを登録していく。

ターミナルはgitbashを使用している。

```bash
eval $(ssh-agent)
ssh-add <sshキーのパス>
```

パスフレーズを打つと登録完了。

その後、`ssh-add -L` を打つとssh-agentに追加されているすべての公開キーが表示されます。

毎度、上記のコマンドをターミナルを開くたびに打つのは面倒なので`.bashrc`とかに入れておきました。

※macはキーチェーンを使うことでターミナル間のパスフレーズを保持可能らしい。

これで、ターミナルを開きなおすと

```bash
Agent pid 2493
Enter passphrase for $$$$:
```

パスフレーズを一度打つと、その後pushする際に毎度パスフレーズを打たないで済む。素晴らしい！！

本題に戻ると、

devcontainer内でsshキーを使用するには

**ローカルでssh-agentが動いていたらdevcontainerでもsshキーが使えますよ**ということなので

ローカルでssh-agentにsshキーを登録し終わったのでdevcontainerを開きなおし再チャレンジ。

```bash
vscode ➜ /app (main) $ git push -u origin main
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Delta compression using up to 8 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (13/13), 3.29 KiB | 105.00 KiB/s, done.
Total 13 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
 * [new branch]      main -> main
```

上手くいきました！！！

開発環境構築は終わったので本題のコードを書いていきましょう(涙
# 参考

https://okash1n.works/posts/how-to-use-git-inside-vscode-dev-container/

https://zenn.dev/nayushi/articles/5d577c93e03a9b