chezmoi 사용법 — 소스 표현과 apply 흐름
chezmoi가 dotfiles를 어떻게 표현하고 적용하는지: 소스 디렉토리(git repo), 파일명에 인코딩된 메타(dot_·private_·encrypted_·.tmpl), 템플릿으로 머신 분기(.chezmoi.hostname·[data]), init→apply와 edit·update 일상 명령, encrypted_·패스워드 매니저로 시크릿, run_ 스크립트로 apply 시 부트스트랩까지 한 장으로.
chezmoi를 쓰기로 했다면(그 선택 기준은 chezmoi vs 심링크 참고), 실제로 알아야 할 건 두 가지다 — dotfiles를 어떻게 표현하나(소스), 그리고 어떻게 적용하나(apply). 이 글은 그 메커니즘과 명령 흐름을 정리한다.
소스 표현 — 파일이 어디에, 어떤 이름으로 사는가
chezmoi의 모든 것은 하나의 소스 디렉토리에서 시작한다.
- 소스 디렉토리:
~/.local/share/chezmoi— 그냥 git 저장소다. 여기 있는 파일들이 홈 디렉토리로 렌더된다. - 파일명이 메타데이터를 인코딩한다. 홈에 그대로 두면 숨김 파일이라 다루기 불편한 것들을, 소스에서는 접두어로 표현한다:
dot_zshrc→~/.zshrc(dot_이 앞의.을 대신)private_/executable_/readonly_→ 렌더된 파일의 퍼미션.tmpl확장자 → 이 파일은 템플릿이니 렌더가 필요하다는 표시
- 템플릿 데이터:
.tmpl파일 안에서{{ .chezmoi.hostname }},{{ .chezmoi.os }},{{ .chezmoi.arch }}같은 내장 변수를 쓸 수 있고,chezmoi.toml에 커스텀 값을 정의해 끌어 쓸 수도 있다.
즉 ~/.local/share/chezmoi/dot_zshrc.tmpl은 “머신별로 렌더될 ~/.zshrc의 원본”이라는 뜻을 파일명만으로 담는다.
템플릿 — 실제로 분기하기
.tmpl 파일은 Go 템플릿 문법으로 머신별 분기를 담는다. 개념보다 예시가 빠르다 — 회사·개인 머신에서 git 이메일을 가르는 dot_gitconfig.tmpl:
1
2
3
4
5
6
7
[user]
name = clang
{{- if eq .chezmoi.hostname "work-laptop" }}
email = developer@work.example.com
{{- else }}
email = developer@example.com
{{- end }}
apply 시점에 .chezmoi.hostname이 평가돼, 이 머신에 맞는 한 줄만 남은 평범한 ~/.gitconfig로 렌더된다. 파일엔 조건문 흔적이 없다 — 분기는 이미 apply 때 끝났다. (.gitconfig는 런타임에 source로 분기할 수 없는 대표적 파일이라, 이런 렌더 분기가 chezmoi를 쓰는 이유 중 하나다.)
자주 쓰는 내장 변수:
.chezmoi.hostname— 머신 이름으로 분기 (가장 흔함).chezmoi.os/.chezmoi.arch—darwin/linux,amd64/arm64로 OS·아키텍처 분기.chezmoi.username— 사용자명
내장 변수로 안 갈리는 값(회사 프록시 주소 등)은 직접 정의한다. ~/.config/chezmoi/chezmoi.toml의 [data]에 넣으면 템플릿에서 {{ .email }}로 끌어 쓴다:
1
2
3
# chezmoi.toml — 이 머신의 값
[data]
email = "developer@work.example.com"
새 머신에서 클론하는 사람마다 자기 값을 넣게 하려면, 소스에 .chezmoi.toml.tmpl을 두고 promptString으로 init 때 프롬프트를 띄운다.
명령 흐름 — init에서 apply까지
1
2
3
4
5
chezmoi init # 소스 repo 생성
chezmoi add ~/.zshrc # 기존 파일을 관리 대상으로 편입 (dot_zshrc로 저장)
chezmoi chattr +template ~/.zshrc # 이 파일을 템플릿으로 전환 (.tmpl 부여)
chezmoi diff # apply하면 무엇이 바뀌는지 미리보기
chezmoi apply # 템플릿을 렌더해 홈에 실제로 씀
흐름을 말로 풀면 이렇다.
chezmoi init— 소스 저장소를 만든다. 이후 모든 편집은 이 저장소 안에서 일어난다.chezmoi add ~/.zshrc— 지금 홈에 있는 실파일을 소스로 가져온다. chezmoi가 알아서dot_zshrc라는 이름으로 저장한다.chezmoi chattr +template ~/.zshrc— 머신별로 내용이 갈려야 하는 파일을 템플릿으로 승격한다. 이제 그 파일 안에서{{ .chezmoi.hostname }}같은 분기를 쓸 수 있다.chezmoi diff— apply를 실행하면 홈 파일이 어떻게 바뀌는지 미리 보여준다. 복사 방식이라 원본과 어긋날(drift) 수 있는 chezmoi에서, 이 미리보기가 안전장치다.chezmoi apply— 템플릿을 이 머신용으로 렌더해 홈에 실제로 쓴다. 편집→반영이 즉시가 아니라 이 단계를 거친다는 점이 심링크 방식과 결정적으로 다른 지점이다.
초기 셋업이 끝나면 일상은 다른 명령 몇 개로 돈다.
1
2
3
4
5
chezmoi edit ~/.zshrc # 소스 파일을 직접 열어 편집 (dot_zshrc를 찾아줌)
chezmoi cd # 소스 저장소로 이동 — git 커밋/푸시는 여기서
chezmoi apply # 편집분을 홈에 반영
chezmoi update # git pull + apply 한 방 (다른 머신에서 밀어둔 변경 당겨오기)
chezmoi managed # chezmoi가 관리 중인 파일 목록
chezmoi edit은 홈의 실파일이 아니라 소스를 연다 — chezmoi에선 항상 소스를 고쳐야 하고, 홈 파일을 직접 고치면 다음 apply에 덮인다(drift). 여러 머신을 쓴다면 한쪽에서 chezmoi cd && git push, 다른 쪽에서 chezmoi update가 기본 리듬이다.
시크릿 — 암호화해서 저장소에 넣기
심링크 방식은 시크릿을 저장소 밖(~/.secrets + gitignore)에 두는 게 정석이다. chezmoi는 반대로 암호화해서 저장소 안에 넣을 수 있다 — 이게 심링크 대비 실질적 차별점이다.
encrypted_접두어 + age(또는 gpg) —encrypted_private_id_rsa처럼 두면 소스엔 암호문으로 저장되고 apply 때 복호화돼 홈에 쓰인다. 키 하나만 안전하게 옮기면 개인키·토큰도 저장소에 담아 재현할 수 있다.패스워드 매니저 연동 — 템플릿 안에서
{{ onepasswordRead "op://..." }},{{ (bitwarden "item" "id").login.password }}같은 함수로 apply 시점에 값을 끌어온다. 저장소엔 시크릿이 아예 안 들어가고 참조만 남는다.
즉 chezmoi에선 시크릿을 “저장소에서 뺄지”가 아니라 “암호화해 넣을지 / 매니저에서 당길지”의 선택이 된다. 여러 머신에 개인키까지 재현하려면 이 기능이 심링크 + .secrets보다 편하다.
apply에 붙는 자동화 — run_ 스크립트 & .chezmoiignore
chezmoi는 apply 때 스크립트를 실행할 수 있다. 파일명 접두어가 실행 시점을 정한다:
run_— apply마다 실행run_once_— 내용이 바뀔 때 딱 한 번. 부트스트랩용(Homebrew 설치 등)run_onchange_— 그 스크립트 내용이 바뀌었을 때만. Brewfile 갱신 시 재설치 같은 데
run_once_before_install-packages.sh에 brew bundle 한 줄을 넣어 두면, 새 머신에서 chezmoi init --apply 한 방에 패키지 설치까지 딸려 온다. 2단계 Brewfile이 여기서 chezmoi 흐름 안으로 들어온다.
머신마다 있어야/없어야 하는 파일은 .chezmoiignore로 가른다 — .gitignore와 같은 문법이고 템플릿도 먹어서, {{ if ne .chezmoi.os "darwin" }}Library/{{ end }}처럼 OS별로 제외할 수 있다.
지우기 — forget·destroy·purge
라이프사이클의 반대편. 핵심은 소스에서 파일만 지워도 홈의 실파일은 안 지워진다(관리만 끊길 뿐)는 것 — 목적별로 명령이 갈린다.
chezmoi forget ~/.zshrc— 소스에서 빼 관리만 중단. 홈 파일은 그대로 둔다.chezmoi destroy ~/.zshrc— 소스와 홈 파일까지 삭제. 되돌릴 수 없으니--dry-run으로 먼저 확인.chezmoi purge— 대상 dotfile은 남겨 두고 chezmoi의 설정·상태·소스 디렉터리를 제거. 먼저chezmoi source-path와 원격 push 상태를 확인하고, 소스까지 버릴 의도가 분명할 때만 실행한다. 설정만 일부 지우고 싶다면purge대신chezmoi doctor로 실제 경로를 확인한 뒤 해당 항목만 명시적으로 처리한다.
흔한 오해 하나: 소스에서 파일만 지우고 apply하면 홈엔 고아 파일로 남는다. chezmoi는 관리하지 않게 된 파일을 임의로 지우지 않기 때문. 홈에서도 없애려면 destroy나 .chezmoiremove를 써야 한다.
핵심 한 방 — init –apply
chezmoi를 쓰는 진짜 이유에 가장 가까운 명령은 이것 하나다.
1
chezmoi init --apply <repo> # 클론 + 렌더 + 적용을 한 번에
새 머신에서 이 한 줄이면 저장소를 클론하고, 이 머신용으로 템플릿을 렌더하고, 홈에 적용하는 것까지 끝난다. “남이 클론해 자기 머신에서 그대로 돌리게” 하는 공유 경험 — 심링크 방식으로는 주기 어려운 이 지점이 chezmoi의 대표 기능이다.
정리
- 소스는
~/.local/share/chezmoi(git repo) 하나. 파일명 접두어(dot_·private_·executable_·encrypted_)와.tmpl이 메타를 담는다. - 머신 분기는
.tmpl안에서.chezmoi.hostname·.os나[data]커스텀 값으로. 편집은 소스에서 하고chezmoi apply로 렌더해 홈에 반영한다 —diff로 먼저 확인하는 습관이 drift를 막는다. - 일상 리듬은
edit(소스 편집) →cd && git push→ 다른 머신에서update. - 시크릿은
encrypted_나 패스워드 매니저 함수로 저장소 안에서 다룬다. - 지울 땐
forget(관리만 중단) /destroy(홈 파일까지) /purge(chezmoi째)를 목적에 맞게. 소스가 저장소 하위면purge가 저장소를 지우니 주의. - 공유의 핵심은
chezmoi init --apply <repo>— 클론·렌더·(run_once_스크립트로) 설치까지 한 방.
chezmoi를 아직 쓸지 말지 고민 중이라면, 심링크와의 선택 기준은 chezmoi vs 심링크 dotfiles에 정리해 두었다.