Dotfiles Driven Development
dotfiles とは Unix 系 OS で俗に言う設定ファイルのことです。.vimrc
や .zshrc
など設定ファイルの多くは隠しファイルとしてファイル名の頭にドットがつくことからそう呼ばれています。
ほとんどのエンジニアは CLI 環境での開発は避けては通れないものに思います。CLI 環境は「黒い画面」として嫌煙されがちで、CLI になると格段に作業効率がダウンする人も少なく無いです。その作業を効率化するキーとなるのは、設定ファイルの習熟度にあると思います。GUI 開発環境と比べてこちらはテキストベースでカスタマイズできるため、究極まで自分好みに合わせることが可能です。こうした dotfiles のカスタマイズ駆動で開発をすることで効率性は大きく向上します。
また、基本的にソフトウェアの設定は時間コストと学習コストがかかるものです。これらを失うのは大変なディスアドバンテージとなるので、変更履歴の保存とバックアップを兼ねて GitHub で管理しましょう。
リポジトリの作成手順
(GitHub のアカウント取得から ssh の設定などは割愛します)
- GitHub にて username/dotfilesというリポジトリ名で作成
mkdir dotfiles && cd dotfiles
- ホームディレクトリに転がっているドットファイルを
dotfiles/
に移動する - シンボリックリンク用のスクリプトファイルを用意する
- あとは
git init
からgit push
まで
以上であなただけの dotfiles リポジトリは完成します。しかし、筆者がしばらくこの dotfiles を運用してみてわかったことや便利だと思ったことを後述する運用方法にて説明します。
参考:
- ナウなヤングのためのgithub入門講座 -基本機能からdotfiles管理まで- - 2011年12月12日
- iTerm2 + zsh + tmux + vim で快適な256色ターミナル環境を構築する - 2012年2月11日
- dotfilesをgithubで管理する! - 2012年3月5日
- dotfilesをgithubで管理し、Vundleを導入する - 2012年3月24日
- githubとhomesickでドットファイルをオシャレに管理する - 2013年4月9日
- GitHub と homesick を使って複数 Mac 間で dotfiles を同期する - 2014年1月10日
- DotfilesをGitHubで管理する - 2014年2月7日
- dotfilesをgithubで管理 - 2014年3月9日
- dotfilesをGithubで管理するときの3つのポイント - 2014年3月21日
- dotfilesをGitHubで管理する方法 - 2014年5月11日
- dotfileの管理をGithubに置いて一元化したりどこでもセットアップできるようにする - 2014年7月13日
- Homeshickでdotfilesを管理することにした - 2014年8月20日
- GitHubにdotfilesを登録してみたよ - 2014年8月20日
- イケてると思う dotfiles の管理方法 - 2014年12月21日
dotfiles の運用方法
dotfiles をしばらく運用してきて分かったことがあります。それは以下のことに沿ってリポジトリを整備することです。
それでは一つずつ見ていきましょう。
ワンコマンドでインストールできる
GitHub にある dotfiles リポジトリの多くは以下のようなワンコマンドですべてがインストールできるような構成になっていることが多いです。
curl https://{URL}/install.sh | bash
例:Homebrew(ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
)
wget
や curl
のワンライナーですべての作業(ダウンロード、デプロイ、イニシャライズ)が完結できるようにしましょう。ターミナルの設定とはいえ、環境の再構築は簡単にできるに越したことはないです。ワンコマンドですぐに再構築できるのは環境が壊れることを恐れさせない強みになります。
デプロイとイニシャライズは切り分ける
デプロイ1とは
多くのソフトウェアはホームディレクトリにあるドットファイルを設定ファイルとして起動時に読み込みます(例:
.vimrc
)。つまり、ダウンロードした dotfiles リポジトリにあるドットファイルをホームディレクトリにリンクする必要があります。コピーするだけでも同等の効果を得ることが出来ますが、シンボリックリンクを貼ることでドットファイルを書き換えても自動的に本家(リポジトリでホスティングされているドットファイル)も更新されgit push
するだけで済むからです。このリンクすることを便宜上、デプロイと呼ぶことにします。デプロイ用のスクリプトファイルは大抵install.sh
やlink.sh
、setup.sh
といった名前でホスティングされています。イニシャライズ2とは
dotfiles リポジトリには多くの場合、これらのドットファイルの他に環境設定用の
*.sh
ファイルが同梱されています。例えば、エディタのカスタムビルドや、パッケージマネージャを通したソフトウェアのインストールやその設定などです。便宜上、これら設定の実行をイニシャライズと呼びます。
このイニシャライズと、デプロイは完全に切り分けるべきです。なぜなら、イニシャライズはその名の通り、リポジトリをダウンロードしたときにしか実行しないからです。しかし、デプロイはリンクが切れてしまったり、リポジトリに新規ファイルがコミットされたときなど、デプロイし直すことは多々あります。
また、どこかのサーバを借りて開発にするときなど、大抵の場合は設定ファイルのデプロイさえできればよく、イニシャライズは必要ありません。
dotfiles のルートディレクトリのディレクトリ構造は簡潔にする
dotfiles のルートディレクトリは GitHub でのファーストビューです。ゴロゴロと規則性もなくディレクトリが多数配置されていては、どこに何があるのかがわかりにくくなり、管理も煩雑化しナンセンスです。UNIX 系 OS の慣習に倣ったディレクトリ命名で役目を明確化させるのがスマートです(例:bin
)。
実際の dotfiles を例に解説
筆者の環境を例に、以上のルールを当てはめて紹介します。
詳しくは README をご覧ください。
ワンコマンドでインストールできる
上の例に示したように、curl
などのダウンローダーで一発完了できます。
bash -c "$(curl -L dot.b4b4r07.com)"
(注:URL を短くするために dot.b4bb4r07.comは GitHub の dotfiles リポジトリにリダイレクトされるようになっています)
このワンライナーが一体何をするかは README にもありますが、
- リポジトリのダウンロード
- ドットファイルのデプロイ
- (任意で)イニシャライズ
です。
複数の処理ありますが、ワンコマンドをコピペ ENTER するだけで完了するのでめっちゃ簡単です。
仕組みとしては、etc/
にある install
という名前のスクリプトファイルを Web を介して実行しているだけです(ローカルでは make install
3すると、アップデート・デプロイ・イニシャライズが可能です)。
デプロイとイニシャライズは切り分ける
筆者の場合、link.sh
のようなデプロイ用のスクリプトファイルの代わりに、Makefile
を使用しています。Makefile とはプログラムのビルド作業を自動化するツールですが、決まったプロトコルを順番に実行する用途にはもってこいの代物です。これを make deploy
と make init
として利用することで、簡単に切り分けることが出来ます。
DOTFILES_EXCLUDES:= .DS_Store .git .gitmodules .travis.yml
DOTFILES_TARGET:=$(wildcard .??*) bin
DOTFILES_DIR:=$(PWD)DOTFILES_FILES:=$(filter-out $(DOTFILES_EXCLUDES), $(DOTFILES_TARGET))deploy:
@$(foreach val, $(DOTFILES_FILES), ln -sfnv $(abspath $(val))$(HOME)/$(val);)init:
@$(foreach val, $(wildcard ./etc/init/*.sh), bash $(val);)
ドットファイルとして、$(wildcard .??*)
として指定しています。これは .
や ..
などの要素を回避しつつ、すべてのドットファイルをワイルドカードで指定しています。さすがにこれでは関係のないドットファイル(.DS_Store
、.git
)も含まれてしまうのでホワイトリスト方式でこれをフィルタリングします。
ドットファイルを一括でターゲットとすることで、新規ドットファイルが追加されてもこの Makefile を修正する必要がないので便利です(追加修正し忘れでリンクされないなどよくある)。
また、イニット用の *.sh
ファイルはまとめて、etc/init/
以下に配置しています。こうすることで、Makefile から foreach
でまとめて実行することができます。
ちなみに、etc/init/
には以下の様なスクリプトファイルが保存されています。
- Vim のカスタムビルド
- ホームディレクトリにあるディレクトリ名の英語化
- Zsh プラグインマネージャ Antigen のインストール
- シンタックスハイライタ Pygments のインストール
- OS X の
defaults
コマンド群の実行
dotfiles のルートディレクトリのディレクトリ構造は簡潔にする
筆者の場合、dotfiles のリポジトリルートには以下のディレクトリしか配置していません。
bin/
自作のコマンドスクリプトやバイナリなどの保管場所。
.zshrc
などではPATH=$PATH:~/bin
などとしてパスを通します。ドットファイルに加えてbin/
もデプロイのリストにあるので、ホームディレクトリにリンクされます。make list
でデプロイされるファイル・ディレクトリの列挙が可能です。doc/
ドキュメンテーションがメインですが、ある意味エクストラファイルの保存場所です。設定ファイルでも、自作コマンドでもないもの(マニュアル他、README 用の画像など)が配置されます。
etc/
設定用のスクリプトファイルや、コード関連のファイルの保存場所です。また、
etc/init
以下にあるスクリプトは dotfiles のインストール時のイニシャライズに使用されます。doc/
との違いは、コード片か非コード片かだけです。
以上の3ディレクトリと Makefile
、README.md
以外はすべてドットファイルです。見渡し良好でどのディレクトリに何があるか、どんな役割のディレクトリかがすぐに分かります。
各種プラグインについて
Vim や Zsh などプラグインで設定をカスタマイズするソフトウェアも多く、そのプラグインの管理や扱いについても注意すべきでしょう。各種プラグインはリポジトリから切り離すことが必要です。
ただのディレクトリとして取り込む
ダウンロードしたプラグインを、それぞれのプラグインディレクトリ(~/.vim/bundle
や ~/.antigen
)にコピーするだけです。しかし、この方法は次のような欠点があります
- プラグインのアップデートの取得が大変。自分で更新を確認して上書きコピーする必要がある
- 大きいプラグインの場合、自分のリポジトリのサイズも肥大化する
- プラグイン数が多いとダウンロードに時間が掛かる
Git のサブモジュールとして取り込む
プラグインは GitHub などで管理されていることが多いので、アップデートなどの更新を取得するために Git のサブモジュールとして取り込む方法です。
しかし、これも自分のリポジトリサイズを大きくしたりダウンロードに時間が掛かるだけでなく、複雑な Git 操作を強いられるため初心者にはお勧めできません。
プラグインマネージャを使用する
Vim も Zsh もそれぞれ、NeoBundleや Antigenといった有名なプラグインマネージャがあるのでそれを利用しましょう。
Vim
筆者の場合、Vim の起動時に NeoBundle がなかった場合にのみ実行できる
:NeoBundleInit
というコマンドを定義しています。.vimrclet $VIMBUNDLE ='~/.vim/bundle'let $NEOBUNDLEPATH = $VIMBUNDLE . '/neobundle.vim'if stridx(&runtimepath, $NEOBUNDLEPATH)!=-1" If the NeoBundle doesn't exist. command! NeoBundleInit try|calls:neobundle_init() \|catch/^neobundleinit:/ \| echohl ErrorMsg \|echomsgv:exception \| echohl None \|endtryfunction!s:neobundle_init()redraw| echo "Installing neobundle.vim..."if!isdirectory($VIMBUNDLE)callmkdir($VIMBUNDLE,'p') echo printf("Creating '%s'.", $VIMBUNDLE)endifcd $VIMBUNDLE if executable('git')call system('git clone git://github.com/Shougo/neobundle.vim')ifv:shell_error throw'neobundleinit: Git error.'endifendifsetruntimepath& runtimepath+=$NEOBUNDLEPATH call neobundle#rc($VIMBUNDLE)try echo printf("Reloading '%s'", $MYVIMRC) source $MYVIMRC catch echohl ErrorMsg echomsg'neobundleinit: $MYVIMRC: could not source.' echohl None return0finallyechomsg'Installed neobundle.vim'endtryechomsg'Finish!'endfunctionautocmd!VimEnter * redraw \ | echohl WarningMsg \ | echo "You should do ':NeoBundleInit' at first!" \ | echohl None endif
これは、NeoBundle がないときに Vim を起動すると
:NeoBundleInit
を実行するように促し、するとgit clone
で NeoBundle をインストールし、そのまま大量のプラグインをインストールします。Zsh
Zsh ではログイン時に起動されるべき項目などを
zsh_at_startup
として関数化してあります。antigen の初期化や tmux の起動などです。tmux については別記事で詳細に解説してあるのでそちらも参考にしてみてください。.zshrcantigen_plugins=("brew""zsh-users/zsh-completions""zsh-users/zsh-history-substring-search""zsh-users/zsh-syntax-highlighting""hchbaw/opp.zsh"#"tarruda/zsh-autosuggestions""b4b4r07/enhancd""b4b4r07/favdir"#"b4b4r07/zsh-vi-mode-visual")function zsh_at_startup(){# ...(省略)... tmux_automatically_attach # Antigenif[[ -f ~/.antigen/antigen.zsh ]];thenecho -e "=> $fg[blue]Setup antigen....$reset_color"local plugin source ~/.antigen/antigen.zsh for plugin in "${antigen_plugins[@]}"doecho"checking... $plugin" antigen bundle "$plugin"done antigen apply echo -e "=> $fg[blue]done$reset_color\n"fi# Hello, Zsh!!echo -e "\n$fg_bold[cyan]This is ZSH $fg_bold[red]${ZSH_VERSION}$fg_bold[cyan] - DISPLAY on $fg_bold[red]$DISPLAY$reset_color\n"}if zsh_at_startup;then zsh_set_utilities zsh_set_prompt zsh_set_completion zsh_set_setopt zsh_set_alias zsh_set_keybind fi
プラグインを自分のリポジトリに取り込む利点は、ワンコマンドで dotfiles をインストールしたときにソフトウェアの設定を完全に再現できることにあります。しかし、プラグインの数が増えるごとに容量も増え、複雑になるのが欠点でした。
そこで重要なのが、シェルやエディタなどの CLI のインフラにあたるところはプラグインなしでも、最低限に快適な作業ができるような設定を心がけるべきです。筆者の場合、エディタに必ず必要と感じているプラグイン(MRU; 最近開いたファイルリストを表示する)を自分製に小型化し、設定ファイルに関数として記述しています。
そして、プラグインはリポジトリから切り離し、それぞれのソフトウェアの中でギリギリまで設定を高めるのがおすすめです。そうすることで、プラグインをインストール出来ない環境や、まったりとダウンロードやインストールが終わるのを待っていられない状況などに即座に開発が開始できます。
まとめ
- dotfiles のインストールはワンコマンドでする
- 3ステップのタスク、後者2つの独立性
- 1.ダウンロード
- 2.デプロイ
- 3.イニシャライズ
- デプロイは簡単にできる
- プラグインはリポジトリから切り離す
dotfiles の設定は楽しい
冒頭にも述べたとおり、設定ファイルのカスタマイズは CLI 環境の生産性を高めることにつながります。とても便利な CLI ライフが手に入るので、GitHub で 「dotfiles」でスターの高いリポジトリを参考にしてみたり、筆者の環境b4b4r07/dotfilesを例にカスタマイズしてみてください。