Mac と Ubuntu で同じ開発環境を作る dotfiles 設計メモ 第1回:全体設計とディレクトリ構成
はじめに
普段使っている開発環境の設定を dotfiles として一元管理しています。
きっかけは、「Mac と Ubuntu を行き来しても同じ操作感で作業したい」という素朴な欲求でした。
最初は単に設定ファイルをまとめたいだけでしたが、いざ両対応にしようとすると、OS ごとのファイル配置、コマンド、クリップボード、IME など、さまざまな違いにぶつかりました。
このシリーズでは、Mac と Ubuntu で同じ開発環境を作るために、dotfiles をどう構成し、どのように OS 差分を吸収しているのかを紹介します。
管理しているのは主に次のツールです。
- zsh
- Ghostty
- tmux
- Neovim
- VS Code Neovim
第1回では、dotfiles 全体の設計方針とディレクトリ構成について書きます。
具体的な Ghostty / zsh / tmux / Neovim の設定例は、第2回以降で扱います。
対象読者
この記事は、次のような人を想定しています。
- Mac と Ubuntu を行き来して開発している人
- dotfiles を作り始めたが、OS 差分の扱いに悩んでいる人
- zsh / tmux / Neovim などの設定を少しずつ自分用に育てたい人
- Linux のファイル配置や環境差分を、実際の設定を通して理解したい人
検証環境
この記事の内容は、以下のような環境を前提にしています。
| 項目 | 環境 |
|---|---|
| macOS | TODO: 例 macOS 15.x
|
| Ubuntu | TODO: 例 Ubuntu 24.04 LTS
|
| Ubuntu のセッション | X11 |
| シェル | zsh |
| ターミナル | Ghostty |
| エディタ | Neovim / VS Code Neovim |
| ターミナルマルチプレクサ | tmux |
| Linux 側のクリップボード連携 | xsel |
| Linux 側の IME | TODO: 例 fcitx5
|
Ubuntu 側は X11 前提です。
X11 / Wayland の確認は、次のコマンドでできます。
echo "$XDG_SESSION_TYPE"
この記事では、Ubuntu 側で x11 が返る環境を想定しています。
シリーズ構成
この内容は、次の3本に分けて書きます。
- dotfiles 全体設計とディレクトリ構成
- Ghostty / zsh / tmux で OS 差分を吸収する
- Neovim / VS Code Neovim / IME の設定を共通化する
この記事は第1回です。
第1回では、具体的な設定ファイルの細部に入る前に、dotfiles をどういう方針で管理しているかを整理します。
dotfiles を作る目的
dotfiles を作る目的は、単に設定ファイルをバックアップすることだけではありません。
自分の場合は、次のような目的があります。
- 新しいマシンでも同じ操作感を再現したい
- Mac と Ubuntu の設定差分をなるべく小さくしたい
- 設定変更の理由を Git で追えるようにしたい
- シェル、ターミナル、エディタをまとめて管理したい
- 自分の開発環境を理解しながら改善したい
特に Mac と Ubuntu を行き来していると、「普段何気なく使っている設定」が OS に依存していることに気づきます。
例えば、クリップボード連携は macOS では pbcopy が使えますが、Ubuntu では別のコマンドが必要です。
zsh のプラグインも、Homebrew で入れた場合と apt で入れた場合では置かれる場所が変わります。
こうした違いを一つずつ吸収していくことで、dotfiles が単なる設定置き場ではなく、OS の違いを学ぶ材料にもなりました。
設計方針:共通部分と OS 固有部分を分ける
複数 OS で dotfiles を使い回すときに一番効いたのは、共通設定と OS 固有設定を分けることでした。
設定ファイルが OS ごとにコピペで分岐していくと、片方だけ直し忘れて壊れます。
これはアプリケーションコードで共通化を考えるのと同じです。
基本方針は次の通りです。
- 共通設定は 1 か所に寄せる
- OS 固有の設定だけを分離する
- パスやコマンドの違いは小さな関数や条件分岐で吸収する
- できるだけ同じ手順で展開できるようにする
- 例外的な設定は、なぜ分けたのかをコメントに残す
例えば、Mac と Ubuntu で同じ .zshrc を使いたい場合でも、プラグインの配置場所や使えるコマンドは異なります。
そこで、設定全体を OS ごとに丸ごと分けるのではなく、違いが出るところだけを関数や条件分岐に閉じ込めるようにしています。
ディレクトリ構成
ディレクトリは、ツールごとに次のような形に揃えています。
<tool>/.config/<tool>/...
例えば、Neovim なら次のようなイメージです。
nvim/
└── .config/
└── nvim/
├── init.lua
├── lua/
└── lazy-lock.json
Ghostty なら次のようなイメージです。
ghostty/
└── .config/
└── ghostty/
├── config.ghostty
├── base
├── linux
└── macos
tmux は次のようにしています。
tmux/
└── .tmux.conf
zsh は次のようなイメージです。
zsh/
├── .zshrc
└── .zshenv
実際には、これらをホームディレクトリ配下にシンボリックリンクで展開します。
~/.config/nvim -> dotfiles/nvim/.config/nvim
~/.config/ghostty -> dotfiles/ghostty/.config/ghostty
~/.tmux.conf -> dotfiles/tmux/.tmux.conf
~/.zshrc -> dotfiles/zsh/.zshrc
このようにしておくと、リポジトリ内ではツールごとに管理しつつ、実際の配置は各ツールが期待する場所に合わせられます。
なぜ <tool>/.config/<tool> にしているのか
最初は、リポジトリ直下に設定ファイルを並べるだけでもよいと思っていました。
dotfiles/
├── .zshrc
├── .tmux.conf
└── nvim/
ただ、この形だとツールが増えるにつれて、どのファイルがどのツールに対応しているのか分かりにくくなります。
そこで、ツールごとにディレクトリを分けるようにしました。
dotfiles/
├── zsh/
├── tmux/
├── ghostty/
└── nvim/
さらに、~/.config 配下に置くツールについては、リポジトリ内でも .config 以下の構造を再現しています。
nvim/.config/nvim
ghostty/.config/ghostty
こうしておくと、実際にホームディレクトリへ配置したときの形をリポジトリ上でも想像しやすくなります。
シンボリックリンクで展開する
dotfiles は、実体をリポジトリ内に置き、ホームディレクトリ側にはシンボリックリンクを張る形にしています。
例えば、Neovim なら次のようにします。
ln -s ~/dotfiles/nvim/.config/nvim ~/.config/nvim
tmux なら次のようにします。
ln -s ~/dotfiles/tmux/.tmux.conf ~/.tmux.conf
この方法にしておくと、設定ファイルを編集した内容がそのまま dotfiles リポジトリに反映されます。
~/.config/nvim
-> ~/dotfiles/nvim/.config/nvim
つまり、普段通り ~/.config/nvim を編集しているように見えて、実際には Git 管理下のファイルを編集している状態になります。
共通化しすぎない
dotfiles を作り始めると、何でも共通化したくなります。
しかし、すべてを無理に共通化すると、かえって設定が読みにくくなります。
例えば、Mac でしか使わない設定、Ubuntu でしか意味がない設定、特定のターミナルでしか動かない設定を、無理に 1 ファイルへ押し込むと条件分岐だらけになります。
そのため、自分は次のように考えています。
- ほとんど同じなら共通化する
- OS ごとの差分が小さいなら条件分岐で吸収する
- 差分が大きいならファイルを分ける
- 分けた理由が分かるようにコメントを書く
例えば Ghostty では、共通設定を base に置き、Linux 固有設定と macOS 固有設定を別ファイルにしています。
config-file = ?base
config-file = ?linux
config-file = ?macos
一方で zsh のプラグイン読み込みは、ファイルを分けるよりも、候補パスを探索する関数に閉じ込めた方が扱いやすかったです。
このように、ツールごとに「どこまで共通化するか」を考えるようにしています。
dotfiles を通して理解が進んだこと
Mac と Ubuntu で同じ開発環境を作ろうとしたことで、次のような点を調べることになりました。
- ディストリビューションやインストール方法でファイルの置き場所が変わること
- Homebrew の prefix が環境によって異なること
-
/usr/shareと/usr/local/shareの使い分け - 設定を
~/.config配下にまとめる XDG Base Directory の考え方 -
unameや環境変数で実行環境を判定する方法 - X11 / Wayland でクリップボード連携の方法が変わること
- Vim のモードと IME の状態が独立していること
- lockfile でプラグインのバージョンを固定する考え方
どれも単体では小さな知識ですが、「同じ操作感をどの環境でも使いたい」という目標を追ううちに自然と必要になったものです。
dotfiles は、単に設定を保存する場所というより、自分の開発環境を理解するためのメモでもあると感じています。
今回のまとめ
今回は、Mac と Ubuntu で同じ開発環境を作るための dotfiles 全体設計について書きました。
やっていることをまとめると、次の通りです。
- dotfiles はツールごとにディレクトリを分けて管理する
-
~/.config配下に置く設定は、リポジトリ内でも.configの構造を再現する - ホームディレクトリへはシンボリックリンクで展開する
- 共通設定と OS 固有設定を分ける
- すべてを無理に共通化せず、差分が大きいものはファイルを分ける
- 設定ファイルを通して OS ごとの違いを理解する
設定ファイルを共通化する作業は、単に便利にするだけでなく、自分の使っている道具を理解するきっかけにもなりました。
次回
次回は、Ghostty / zsh / tmux の設定を例に、Mac と Ubuntu の差分をどう吸収しているかを書きます。
具体的には、次の内容を扱います。
- Ghostty の設定ファイル分割
- zsh プラグインのパス探索
- tmux のクリップボード連携
- Ubuntu X11 環境での
xsel利用