봄가을 블로그

| 기술

내 Mac 설정을 Git으로 관리하기

Setties를 예시로 symlink, 선언형 의존성 목록, 상태 검증 명령, schema와 pre-commit을 이용해 개인 macOS 개발 환경을 관리합니다.

목차

지속적으로 관리해보자

이전에 개발자 MacBook 종합 세팅 글을 쓴 적이 있습니다. 새 Mac을 받았을 때 무엇을 설치하고, 어떤 설정을 바꾸고, 어떤 앱을 켜야 하는지 순서대로 적어둔 글이었죠. 독자들에게 매뉴얼을 제공하기 위한 목적이었습니다. 매뉴얼은 일회성이긴 해요. 처음에 한 번 읽고, 다음부터는 한 번도 볼 일이 없죠. 내 Mac의 설정(configuration/settings/dotfiles)을 지속적으로 관리할 수 있는 방법은 생각해보지 않았습니다. 무언가가 필요했습니다.

그래서 Setties라는 repo를 만들었습니다. Git으로 제 macOS 개발 환경을 관리하고 있습니다. 다른 사람이 그대로 가져다 쓰라고 만든 범용 설정 관리 프레임워크는 아닙니다. 그렇지만 매뉴얼이 첫 세팅을 도와준 것처럼 이 repo를 지속적인 설정 관리의 시작점으로 잡아도 좋을 것 같습니다.

파일은 Git에 두고, 위치는 올바른 자리에 둔다

설정 파일 관리에서 가장 기본이 되는 문제는요,

.zshrc, .tmux.conf, .p10k.zsh 같은 파일은 Git으로 관리하고 싶습니다. 그런데 각 프로그램은 이런 파일이 홈 디렉터리의 정해진 위치에 있기를 기대합니다.

Setties에서는 이 문제를 symlink로 해결합니다. repo 안에는 scripts/links.json이 있고, 여기에 홈 디렉터리로 연결할 파일을 적어둡니다.

{
"$schema": "./links.schema.json",
"links": [
{
"key": ".zshrc",
"description": "Zsh config"
},
{
"key": ".codex/AGENTS.md",
"description": "User-scope Codex instructions"
},
{
"key": ".tmux.conf",
"description": "tmux config"
}
]
}

그리고 필요한 파일을 링크합니다.

./scripts/bootstrap.py link .zshrc
./scripts/bootstrap.py link --all

예를 들어 repo가 ~/setties 경로에 있다면, ~/setties/.zshrc~/.zshrc 라는 symlink로 세팅됩니다. (기존에 있는 파일은 덮어씌울 수도 있고 패스할 수도 있습니다.)

설치 절차(명령형)보다 필요한 상태(선언형)를 정의

Setties에서는 설치할 프로그램도 관리합니다. scripts/deps.json에서요. 여기에는 설치되어 있어야 하는 CLI, 앱, 디렉터리, 파일을 적어둡니다.

예를 들면 이런 식입니다.

{
"label": "fzf",
"kind": "command",
"target": "fzf",
"depends": ["homebrew"],
"install": "brew install fzf"
}

이를 설명하면,

  • label: 이름입니다. 사람이 읽을 수 있는 식별자이며 ID 역할을 합니다.
  • kind: 검사 조건에 따라 값을 나누었습니다. type 역할을 합니다. 가능한 값은 아래와 같습니다.
    • command: 명령어가 PATH에서 찾아지는지 봅니다.
    • file: 특정 파일이 있는지 봅니다.
    • dir: 특정 디렉터리가 있는지 봅니다.
  • target: 검사 대상입니다. kind에 따라 데이터는 달라질 수 있습니다.
  • depends: 이 항목이 설치되기 전에 먼저 완료되어야 하는 label을 적습니다.
  • install: 참고할 설치 힌트를 적습니다.

여기서 중요한 것은 brew install fzf를 실행한다는 절차가 아니라, fzf라는 command가 존재해야 한다는 상태입니다.

명령형 셸 스크립트는 “무엇을 어떤 순서로 실행할 것인가”를 잘 표현합니다. 반대로 이런 JSON은 “지금 어떤 상태여야 하는가”를 더 잘 표현합니다. Setties는 후자 쪽에 조금 더 무게를 둡니다.

상태를 확인하는 명령

Setties에는 상태 검증 명령이 있습니다.

./scripts/bootstrap.py verify

./v는 이 명령의 짧은 별칭입니다.

./v

실행하면 아래와 같이 보입니다.

./v 실행 결과

./v 실행 결과

이 명령은 현재 Mac을 훑으면서 repo에 적어둔 기준과 맞는지 확인합니다. links, deps 등에 정의된 내용이 실제로 적용되었는지 검사합니다. Git GPG signing 처럼 선언적으로 관리되지 않는 설정도 모두 검사합니다. 추가로 repo 자체를 lint(퀄리티 유지)도 합니다.

  • links.json에 적힌 파일이 제대로 symlink 되어 있는지
  • deps.json에 적힌 command, file, dir이 존재하는지
  • JSON 파일이 schema를 만족하는지
  • JSON formatting이 맞는지
  • .zshrc/Users/<name> 같은 하드코딩된 home path가 들어갔는지
  • Git GPG signing, SSH key, pre-commit hook이 준비되어 있는지
  • macOS defaults 값이 repo의 값과 다른지
  • launchd job이 실제로 로드되어 있는지

이 명령은 AI Agent와 같이 작업할 때 특히 유용합니다. 예를 들어 Agent가 deps.json에 항목을 추가하거나 설정 파일을 수정했다면, 마지막에 무엇을 확인해야 하는지 명확합니다(=추론하느라 토큰을 낭비하지 않습니다). “잘 된 것 같다”가 아니라 검증 명령을 기준으로 삼을 수 있습니다.

AI 작업의 가드레일 (schema, pre-commit, 추가 검증 스크립트)

Setties의 JSON 파일에는 schema가 있습니다.

  • scripts/deps.schema.json
  • scripts/links.schema.json
  • scripts/macos-defaults.schema.json
  • scripts/jobs.schema.json

이 schema 또한 AI Agent가 파일을 수정할 때 유용합니다. Agent는 그럴듯한 JSON을 만들 수는 있지만, 기존 repo의 필드 규칙을 놓칠 수 있습니다. schema는 기본적인 구조를 확인하고, schema로 표현하기 애매한 규칙은 Python 코드의 추가 검증 로직에서 잡습니다.

예를 들어 links.json의 중복 key, 중복 target, source 존재 여부는 validate_links_schema()의 추가 검증에서 확인합니다. deps.json에서 존재하지 않는 dependency label을 참조하거나 dependency cycle이 생기는지도 validate_deps_schema()의 추가 검증에서 확인합니다.

pre-commit도 비슷한 역할을 합니다. 예를 들어 아래와 같은 hook이 있습니다.

  • 커밋 전에 upstream이 최신인지 확인합니다.
  • .zshrc에 하드코딩된 home path가 들어가면 막습니다.
  • pull이나 rebase 이후에는 자동으로 ./v를 실행합니다.

macOS defaults와 launchd

Mac 설정 중에는 GUI로 바꾸는 값이 많습니다. Dock 자동 숨김, Finder 확장자 표시, 키 반복 속도, 자동 대문자 끄기, 트랙패드 탭 클릭, 24시간제 같은 설정입니다.

Setties는 이런 값도 scripts/macos-defaults.json에 적어둡니다. 그리고 현재 시스템 값과 비교할 수 있게 했습니다.

./scripts/bootstrap.py defaults diff
./scripts/bootstrap.py defaults apply --dry-run
./scripts/bootstrap.py defaults apply

launchd job도 비슷합니다. 자동 pull, Homebrew upgrade, Oh My Zsh update, ttydtmux 기반 원격 터미널 같은 작업을 scripts/jobs.json에 적어두고, plist가 최신인지, 실제로 로드되어 있는지 확인합니다.

./scripts/bootstrap.py jobs status
./scripts/bootstrap.py jobs apply
./scripts/bootstrap.py jobs remove

적당히 자동화

자동화하기 애매한 작업은 README.md에 수동 단계로 남겨두었습니다.

예를 들면 Go 공식 설치 프로그램, App Store에서 받아야 하는 앱, Remote Login, Screen Sharing, 전원 관리의 자동 재시작, VS Code Settings Sync 같은 항목입니다. 이런 작업에는 sudo, GUI 조작, 계정 로그인이 필요합니다.

어떻게든 자동화의 방법을 찾아낼 수는 있겠습니다. 하지만 그냥 사람이 직접 몇 번 처리하는게 더 간단하다고 생각했습니다. 양도 그렇게 많지 않구요.

마치며

Mac 설정을 관리하는 방식으로서 몇 가지 포인트를 정리하며 마무리하겠습니다.

  • symlink: Git으로 관리할 파일과 실제 파일이 있어야 하는 위치를 symlink로 분리합니다. 단순하지만 설정 파일 관리의 기본 문제를 잘 풀어줍니다.
  • 선언적 관리: 설치 절차만 적기보다 필요한 상태를 선언적으로 적어둡니다. 어떤 command, file, dir이 있어야 하는지 repo가 알고 있으면 현재 환경과 비교할 수 있습니다.
  • 검증 script: 항상 실행할 수 있는 상태 검증 명령을 둡니다. 이 명령은 사람에게도 쓸모가 있지만, AI Agent가 작업한 뒤 기준점으로 삼기 좋습니다.
  • 유지보수성 규칙: schema, 추가 검증 로직, pre-commit으로 repo의 형식을 지킵니다. 특히 AI-assisted edit에서는 “그럴듯하지만 형식이 깨진 변경”이 생기기 쉬워서 이런 장치가 꽤 도움이 됩니다.

repo: github.com/echoja/setties

감사합니다.