メインコンテンツへスキップ
kt-tech.blog

自宅のWindowsを開発機にする その2: Macの開発環境を作業状態ごとWSLに移す

設定・環境構築10分で読めます

この記事でわかること

  • cloneし直しではなくrsyncで作業状態ごと移した理由
  • 除外設定で転送量を48GBから13GBにした話
  • volta/pyenv/tfenvをmiseにまとめてリポジトリごとに自動切替
  • マシン専用のGitHub鍵と、ディレクトリごとのgitのコミット者切替

その1の状態(Macから ssh desktop でWSLに入れる)

この記事は「自宅のWindowsを開発機にする」連載のその2です。その1で Mac とスマホから WSL に入れるようになったので、今回はそこに Mac の開発環境をそのまま持っていきます。

移すもの

Mac のデスクトップには、個人開発の private(約9GB)と、業務委託先ごとのフォルダが入った Job(約48GB、git リポジトリが20個ちょっと)があります。移し先は WSL の ~/dev/private~/dev/Job にして、中の形は Mac と揃えました。「あのリポジトリどこだっけ」をなくしたかったので。

clone し直さない理由

最初は GitHub から clone し直せばきれいかなと思ったんですが、棚卸ししてみたらこんな感じでした。

  • commit 前の変更が100ファイル超、未 push の commit が100超あるリポジトリがある
  • git worktree をいくつも切って並行作業している
  • .env など git に入っていない設定ファイルが各所にある

clone だとこれが全部消えるので、作業状態ごと rsync でコピーすることにしました。捨てていいものだけ除外して、あとで入れ直す方針です。

rsync の除外設定

.DS_Store
node_modules/
.venv/
venv/
__pycache__/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.next/
.turbo/
.terraform/
.cache/

これだけで Job の 48GB のうち 35GB が除外対象でした。実際に送るのは 13GB ほどで、ほとんど node_modules と仮想環境だったんですよね...

Bash
rsync -aH --partial --info=stats2 --exclude-from=excludes.txt ~/Desktop/Job/ desktop:dev/Job/

ちなみに Mac に最初から入っている /usr/bin/rsync は今だと openrsync(protocol 29)なので、Homebrew で普通の rsync を入れてから使いました。速度は Wi-Fi と小さいファイルの多さのせいで 4MB/s くらいしか出ず、Tailscale の経路が中継(DERP)になってないか疑ったんですが、tailscale status で見ると direct でした。寝かせておけば終わるので、裏で流しっぱなしにしています。

ツールは mise にまとめる

リポジトリごとに必要なものを洗い出してみると、バージョン指定がなかなかバラバラでした。

  • Node: 16 系から 23 系まで(.nvmrc / .node-version / engines
  • Python: 3.11、3.12、3.13(poetry と uv が混在)
  • Terraform: 1.7 から 1.14 まで
  • パッケージマネージャ: npm / pnpm 8・9 / yarn 1 / bun

Mac では volta、pyenv、tfenv の3つで回していたんですが、WSL 側は mise 一本にしました。.nvmrc.python-version.terraform-version も読んでくれるので、フォルダに入るだけでバージョンが切り替わります。

Bash
curl -fsSL https://mise.run | sh
mise settings set idiomatic_version_file_enable_tools node,python,terraform
mise use -g node@22 [email protected] [email protected] bun@latest pnpm@latest
mise use -g tflint@latest tfsec@latest ecspresso@2
# ~/dev 配下の mise.toml は毎回「信頼しますか」と聞かれないように
mise settings add trusted_config_paths /home/koki/dev

pnpm と yarn は corepack に任せて、packageManager の指定に追従させています。初回に「ダウンロードしていいか」と聞いてきて止まるので、COREPACK_ENABLE_DOWNLOAD_PROMPT=0 も入れました。poetry、pre-commit、ruff は uv tool install です。

sudo が要るもの(apt で入れるビルドツール、DB クライアント、LibreOffice と日本語フォント、ffmpeg、Docker Engine、gh / gcloud / az / aws)は1本のスクリプトにまとめて、WSL 側の tmux で走らせてパスワードだけ手で入れました。Docker は Windows の Docker Desktop ではなく、WSL の中に Docker Engine を直接入れています。systemd が動いていれば普通の Ubuntu と同じように入るので。

依存パッケージの入れ直し

除外した node_modules.venv は、lockfile を見て入れ直すスクリプトでまとめて入れました。やっていることは単純です。

  • package-lock.jsonnpm ci(ダメなら npm install
  • pnpm-lock.yamlpnpm install --frozen-lockfile
  • yarn.lockyarn install --frozen-lockfile
  • bun.lockbun install
  • uv.lockuv sync
  • poetry.lockpoetry install --no-root

各ディレクトリに入ったら mise install してから動かすので、古い Node を指定しているリポジトリもそのバージョンで入ります。失敗しても止めずに最後に一覧を出すようにしていて、private の分は8か所とも一発で通りました。

GitHub はマシン専用の鍵で

WSL には GitHub 用の鍵がなかったので、Mac の鍵をコピーするのではなく、デスクトップ専用の鍵を作って登録しました。どっちかのマシンを手放すときに、その鍵だけ消せば済むので。

Bash
# desktop 側
ssh-keygen -t ed25519 -N "" -C "koki@kt-desktop" -f ~/.ssh/id_ed25519
# Mac 側(gh に鍵登録の権限を足してから)
gh auth refresh -h github.com -s admin:public_key
gh ssh-key add kt-desktop.pub --title kt-desktop

gh auth refresh はブラウザでの承認が挟まるので、ここも tmux で走らせてワンタイムコードだけ自分で入れています。ちなみに Claude Code の auto mode では、「GitHub アカウントに鍵を足す」操作は認証情報を増やすものとして一度止められて、自分が明示的に OK してから進みました。これはちゃんと止まってくれていいなと思っています。

git のコミット者をディレクトリごとに切り替える

業務委託先のうち1社だけは会社のメールアドレスで commit したかったので、includeIf で切り替えています。

[user]
	name = j19015
	email = (個人のアドレス)
[includeIf "gitdir:~/dev/Job/<業務委託先A>/"]
	path = ~/.gitconfig-<業務委託先A>

Mac 側は全部個人のアドレスで commit していたので、移植を機に整理できたのはちょっとよかったです。

コピーが終わったあとにやったこと

Job のコピーは、除外後 14.5GB を Wi-Fi で 4〜6MB/s、だいたい40分で終わりました。で、コピーしただけだとちゃんとは動かなくて、ここからが地味に長かったんですよね。

worktree のパスを付け替える

git worktree は、worktree 側の .git ファイルと、本体側の .git/worktrees/*/gitdir にお互いの絶対パスが書かれています。ここに Mac のパスが入ったままなので、全部 WSL のパスに置き換えました。対象は38ファイルでした。

Bash
grep -rlF '/Users/<ユーザー>/Desktop/' --include=gitdir ~/dev/*/.git ~/dev/*/*/*/.git 2>/dev/null
# worktree 側の .git ファイルと、本体側の gitdir を sed で置換
sed -i 's|/Users/<ユーザー>/Desktop/|/home/koki/dev/|g' <対象ファイル>
git worktree list   # 全部 prunable にならずに出ればOK

git worktree repair でも直せるんですが、数が多かったのでまとめて置換しています。あと、本体の .git/configcore.hooksPath にも Mac のパスが残っていたので、これも見落とさないほうがいいです。

Mac 由来の git 設定を直す

気づかなかったところが2つありました。

  • core.ignorecase = true が31リポジトリに残っていた。 Mac のファイルシステムは大文字小文字を区別しないので git が勝手に true にしているんですが、Linux でこのままだと「大文字小文字だけのリネーム」を見落とします。false に戻しました
  • グローバルの gitignore を移し忘れていた。 Mac の ~/.config/git/ignore**/.claude/settings.local.json を入れていたので、desktop でだけ .claude/ が未追跡に出てきて、あれっとなりました
Bash
for r in $(find ~/dev -name .git -maxdepth 4 -prune | xargs -n1 dirname); do
  git -C "$r" config --local core.ignorecase false
done

本当に同じ状態か確かめる

最後に、Mac と desktop の全リポジトリで git status --short を取って突き合わせました。差分は、除外した .DS_Store.turbo/、あと出力の並び順だけ。未 commit の変更もちゃんと同じ状態で移っていたので、ここでようやく安心できました。

Job の依存の入れ直し

上のスクリプトを Job にも流したら、117か所中101か所が一発で通りました。落ちた原因は3種類です。

  1. corepack の既定の pnpm が新しすぎた。 最新の pnpm 12 が選ばれて、pnpm 8 時代の lockfile(v6)を読めませんでした。そこは npx pnpm@8 で入れています
  2. 設定だけの pnpm-workspace.yaml が pnpm 9 だとエラーになる。 中身が allowBuilds だけのファイルで、pnpm 9 だと packages field missing で落ちます。Mac で実際に使っていたのは 10.28.2 だったのでそれに合わせました。決め手は Mac 側の node_modules/.modules.yaml で、ここに使った pnpm のバージョンが残っているんですよね
  3. uv が Python 3.14 を選んでビルドに失敗する。 Python のバージョン指定がないプロジェクトだと、uv が一番新しい 3.14 を選んで、pyarrow や pydantic-core のビルドで落ちました。uv sync --python 3.13 で解決です

最終的には全部通りました。pnpm の既定は corepack と mise の両方で 10.28.2 に固定しています。ちなみに並行で流していたらデスクトップのファンが唸り出して、ちょっと焦ったんですが、負荷を見たら16コア中3〜4コア分くらいでした笑

移植で学んだこと

  • 差分を見るときは「元のマシンで実際に使っていたバージョン」が一番の手がかり。lockfile や .modules.yaml に残っている
  • ファイルシステムごとに git が勝手に決める設定(core.ignorecase)があるので、OS をまたぐときは要注意
  • 最後に git status を突き合わせると、移植が正しくできたか簡単に確かめられる

次回(その3)は、Claude Code の設定・メモリ・複数アカウントの切替を移した話です。

自宅WSL開発機

5
  1. 1自宅のWindowsを開発機にする その1: TailscaleでMacとスマホからWSLに入る
  2. 2表示中自宅のWindowsを開発機にする その2: Macの開発環境を作業状態ごとWSLに移す
  3. 3自宅のWindowsを開発機にする その3: Claude Codeの設定とメモリを引っ越す
  4. 4自宅のWindowsを開発機にする その4: Orcaを入れてWSLのリポジトリを扱う
  5. 5自宅のWindowsを開発機にする その5: Orcaで仕事用アカウントと会話履歴を正しく扱う
この連載の一覧を見る