Devdotfiles환경설정

dotfiles 관리, GNU Stow로 정착한 이야기

2026.04.18

dotfiles 관리 도구만 세 번 갈아탔다

새 노트북을 받을 때마다 환경 설정을 다시 한다는 게 너무 번거로웠다. .zshrc, .gitconfig, .tmux.conf, .config/nvim/... 매번 같은 파일을 다시 만들고 있었다.

처음에는 git 레포에 통째로 넣고 bash 스크립트로 심볼릭 링크를 만들었다. 그 다음에는 chezmoi라는 도구로 갈아탔다. 그 다음에는 yadm을 시도했다. 그러다 결국 GNU Stow에 정착했다.

가장 단순한 게 가장 오래 살아남았다. 이 글은 그 여정과, 왜 Stow가 답이었는지에 대한 회고다.

dotfiles 관리의 본질

이름만 거창하지 결국 두 가지 일이다.

  1. 설정 파일들을 git 레포에 모은다
  2. 새 머신에서 그 파일들을 홈 디렉토리에 적절히 배치한다

문제는 2번이다. .zshrc~/에, init.lua~/.config/nvim/에 있어야 한다. 폴더 구조가 다른 파일들을 한 레포에 모아두면서 어떻게 원래 위치로 보낼지가 핵심이다.

시도 1: bash 스크립트

처음 만든 방법이다. 레포 구조를 홈 디렉토리와 동일하게 만들고, 셸 스크립트로 일괄 심볼릭 링크를 만들었다.

#!/bin/bash
# install.sh
 
ln -sf $PWD/.zshrc ~/.zshrc
ln -sf $PWD/.gitconfig ~/.gitconfig
mkdir -p ~/.config/nvim
ln -sf $PWD/.config/nvim/init.lua ~/.config/nvim/init.lua
# ...100줄 더

처음에는 잘 됐다. 파일이 늘어나면서 install.sh가 200줄을 넘었다. 새 파일을 추가할 때마다 스크립트도 같이 수정해야 했다. 한 번씩 빠뜨려서 동기화가 안 됐다.

시도 2: chezmoi

dotfiles 전용 도구다. 설정 파일에 템플릿을 적용할 수 있고, 머신마다 다른 값(예: 회사 이메일 vs 개인 이메일)을 분기할 수 있다.

chezmoi init
chezmoi add ~/.zshrc
chezmoi apply

기능이 많다. 너무 많다는 게 문제였다.

  • 템플릿 문법(Go template)을 익혀야 한다
  • chezmoi managed, chezmoi diff, chezmoi update 등 명령어가 많다
  • 진짜 dotfiles의 어디까지가 템플릿이고 어디까지가 정적 파일인지 구분이 헷갈린다

머신 간 분기가 정말 필요한 사람에게는 좋겠지만, 나는 단일 OS(macOS)에서 1~2대만 쓴다. 도구가 내 사용 사례에 비해 너무 컸다.

시도 3: yadm

Yet Another Dotfiles Manager의 약자. git을 그대로 쓰면서 홈 디렉토리를 git working directory로 다루는 도구다.

yadm clone https://github.com/me/dotfiles
yadm add ~/.zshrc
yadm commit -m "update zshrc"

git에 익숙한 사람이라면 자연스럽다. 다만 한 가지 단점이 있었다. 홈 디렉토리 전체가 git working directory가 된다. yadm status를 치면 추적 안 된 파일이 수천 개 나온다. .gitignore 관리가 까다롭다.

또 yadm으로 관리되는 파일과 일반 파일이 같은 경로에 섞여 있어서, "이 파일이 dotfiles에 들어 있나?"를 매번 확인해야 했다.

GNU Stow에 정착

Stow는 위 도구들과 비교하면 원시적이다. 심볼릭 링크를 자동으로 만들어주는 작은 유틸리티가 전부다. 1996년에 만들어진 도구다.

설치는 한 줄.

brew install stow

기본 사용법은 단순하다. 홈 디렉토리에 두고 싶은 파일을 패키지(폴더)로 묶어서 레포에 둔다.

dotfiles/
├── zsh/
│   └── .zshrc
├── git/
│   └── .gitconfig
├── nvim/
│   └── .config/
│       └── nvim/
│           └── init.lua
└── tmux/
    └── .tmux.conf

각 패키지는 홈 디렉토리에서 보일 구조를 그대로 가진다. nvim/.config/nvim/init.lua~/.config/nvim/init.lua로 링크된다.

레포 안에서 한 줄.

stow zsh git nvim tmux

끝이다. 모든 파일이 홈 디렉토리에 심볼릭 링크로 연결된다. 새 패키지를 추가하면 stow newpkg 한 줄.

언링크도 한 줄.

stow -D nvim   # nvim 패키지 링크 제거

스크립트도 없고, 템플릿도 없고, 별도 툴 명령어도 없다. 이 단순함이 답이었다.

실제 디렉토리 구조

내 dotfiles 레포 구조다.

dotfiles/
├── README.md
├── install.sh           # brew install + stow 자동화
├── zsh/
│   ├── .zshrc
│   └── .zsh/aliases.sh
├── git/
│   └── .gitconfig
├── tmux/
│   └── .tmux.conf
├── starship/
│   └── .config/starship.toml
├── nvim/
│   └── .config/nvim/...
├── claude/
│   └── .claude/settings.json
└── vscode/
    └── Library/Application\ Support/Code/User/settings.json

패키지를 영역별로 분리해뒀다. 새 머신에서 모든 걸 다 깔지 않을 수 있다. 예를 들어 서버에서는 nvim과 tmux만, 노트북에서는 전부.

# 서버에서
stow nvim tmux
 
# 노트북에서
stow -t ~ */

stow -t ~ */는 모든 패키지를 홈 디렉토리로 링크하라는 명령이다.

install.sh 자동화

새 머신을 받으면 한 번만 실행할 스크립트.

#!/bin/bash
set -e
 
# 1. brew 깔기
if ! command -v brew &> /dev/null; then
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
fi
 
# 2. brew bundle로 패키지 설치
brew bundle --file=Brewfile
 
# 3. dotfiles 링크
stow -t ~ */
 
# 4. zsh 기본 셸로 설정
if [ "$SHELL" != "$(which zsh)" ]; then
    chsh -s $(which zsh)
fi
 
echo "✓ Setup complete"

Brewfile에는 brew로 깔 패키지 목록을 적어둔다. (이걸 별도 패키지 매니저로 분리하지 않는 이유는 단순함을 유지하려고.)

새 노트북에서 git clone./install.sh 한 번. 5분 안에 환경 복원이 끝난다.

작은 함정 몇 가지

함정 1: 중첩된 디렉토리 구조

stow -t ~ */은 폴더 단위로 링크를 만들 수 있다. 예를 들어 ~/.config/nvim 자체를 심볼릭 링크로 만들지, 아니면 그 안의 파일 하나하나를 링크로 만들지 결정한다.

기본 동작은 이미 존재하는 디렉토리에는 파일 단위로, 존재하지 않는 디렉토리는 폴더 자체를 링크한다. 보통 이게 안전하다.

만약 ~/.config/nvim이 이미 존재하면 그 안의 파일들을 개별 심볼릭 링크로 만든다. 직접 만든 파일이 충돌하면 stow가 멈추고 알려준다.

함정 2: 비밀 정보가 섞인다

.gitconfig에 회사 이메일이 들어가 있거나, .aws/credentials에 키가 있으면 git에 푸시되면 안 된다. dotfiles 레포는 보통 public이다.

해결: 비밀 정보가 들어가는 파일은 stow로 관리하지 않는다. 별도 1Password나 Bitwarden 등으로 따로 관리하고, 새 머신에서 직접 만든다.

함정 3: 절대 경로

설정 파일에 절대 경로(/Users/me/...)를 박아두면 새 머신에서 경로가 다르다. $HOME 환경 변수를 쓰거나 ~를 쓴다.

정리

dotfiles 관리 도구를 세 번 갈아탄 후 정착한 답은 가장 오래된 도구였다. GNU Stow는 단순하고, 학습할 게 거의 없고, 깨질 일이 없다. 도구가 단순할수록 평생 쓰기 좋다는 것을 새삼 느꼈다.

내 셋업의 본질은 두 줄이다.

git clone https://github.com/me/dotfiles
cd dotfiles && stow -t ~ */

그 위에 Brewfile이 패키지를 깔고, install.sh가 두 줄을 자동화한다. 수년째 그대로 쓰고 있다. 도구가 안 바뀐다는 게 안정성이다.

dotfiles 도구를 고민 중이라면, 일단 Stow를 써보길 권한다. 한 시간이면 셋업 끝난다. 더 강력한 도구가 필요한 시점이 오면 그때 옮기면 된다. 대부분은 그 시점이 안 온다.