ระบบจัดการ Dotfiles กลางและแยกรายการแอปพลิเคชันระหว่างเครื่องส่วนตัว (personal) และเครื่องทำงาน (work) โดยใช้ chezmoi ควบคู่กับ Homebrew Bundle พร้อมระบบ Auto-sync อัตโนมัติด้วย macOS launchd
.
├── .chezmoi.toml.tmpl # Template ถาม Role ครั้งแรกตอน chezmoi init
├── dot_gitconfig # Git config กลางที่ใช้ร่วมกัน
├── dot_zshrc # Zsh config กลางที่ใช้ร่วมกัน
├── dot_config/
│ └── brew/
│ ├── Brewfile.personal # Homebrew packages ของเครื่อง Personal
│ ├── Brewfile.work # Homebrew packages ของเครื่อง Work
│ ├── manual-apps.personal.txt # ลิสต์แอปนอก Brew ของ Personal
│ └── manual-apps.work.txt # ลิสต์แอปนอก Brew ของ Work
├── dot_local/
│ └── bin/
│ ├── executable_cz-sync-apps # สคริปต์ดัมป์ Brewfile และ Manual apps
│ └── executable_dot-sync # สคริปต์หลักรัน Dump + Git Sync + Apply
├── Library/
│ └── LaunchAgents/
│ └── com.user.dotsync.plist # Service ตั้งเวลาทำงานอัตโนมัติด้วย launchd
└── run_onchange_darwin-install-packages.sh.tmpl # Auto-run brew bundle เมื่อ Brewfile เปลี่ยน
{{- $role := promptChoiceOnce . "role" "Machine role" (list "personal" "work") -}}
[data]
role = {{ $role | quote }}{{- $brewfile := joinPath .chezmoi.sourceDir "dot_config/brew" (printf "Brewfile.%s" .role) -}}
{{- if stat $brewfile -}}
#!/usr/bin/env bash
set -euo pipefail
# Brewfile hash: {{ include (printf "dot_config/brew/Brewfile.%s" .role) | sha256sum }}
echo "==> Syncing Homebrew packages for role: {{ .role }}..."
brew bundle --file="${HOME}/.config/brew/Brewfile.{{ .role }}"
{{- end -}}#!/usr/bin/env bash
set -euo pipefail
ROLE=$(chezmoi execute-template '{{ .role }}')
BREW_DIR="$(chezmoi source-path)/dot_config/brew"
if [[ -z "$ROLE" ]]; then
echo "Error: Machine role not found."
exit 1
fi
mkdir -p "$BREW_DIR"
echo "==> Updating Brewfile.${ROLE}..."
brew bundle dump --force --file="${BREW_DIR}/Brewfile.${ROLE}"
echo "==> Updating manual-apps.${ROLE}.txt..."
comm -23 \
<(ls -1 /Applications ~/Applications 2>/dev/null | grep '\.app$' | sed 's/\.app$//' | tr '[:upper:]' '[:lower:]' | sort -u) \
<(brew list --cask 2>/dev/null | tr '[:upper:]' '[:lower:]' | sort -u) \
> "${BREW_DIR}/manual-apps.${ROLE}.txt"
echo "==> Sync completed for ${ROLE}. Check changes with: chezmoi cd && git status"#!/usr/bin/env bash
set -euo pipefail
# ระบุ PATH ให้ครอบคลุมการรันผ่าน launchd
export PATH="/opt/homebrew/bin:/usr/local/bin:${HOME}/.local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
CZ_DIR="$(chezmoi source-path)"
echo "==> [$(date '+%Y-%m-%d %H:%M:%S')] Starting dot-sync..."
# 1. ดัมป์ลิสต์แอปและ brew packages ล่าสุด
cz-sync-apps
# 2. Pull remote ล่าสุดแบบ auto-stash rebase
chezmoi git pull -- --autostash --rebase
# 3. Commit & Push ถ้ามีไฟล์เปลี่ยนแปลง
if [[ -n $(git -C "$CZ_DIR" status --porcelain) ]]; then
ROLE=$(chezmoi execute-template '{{ .role }}')
git -C "$CZ_DIR" add -A
git -C "$CZ_DIR" commit -m "sync: $(date '+%Y-%m-%d %H:%M:%S') [${ROLE}] (auto)"
git -C "$CZ_DIR" push
echo "==> Pushed updates successfully."
else
echo "==> Nothing new to commit."
fi
# 4. Apply configuration ล่าสุดลงเครื่อง
chezmoi apply<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "[http://www.apple.com/DTDs/PropertyList-1.0.dtd](http://www.apple.com/DTDs/PropertyList-1.0.dtd)">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.dotsync</string>
<key>ProgramArguments</key>
<array>
<string>/bin/bash</string>
<string>-c</string>
<string>exec "${HOME}/.local/bin/dot-sync"</string>
</array>
<!-- รันอัตโนมัติทุกวันเวลา 19:00 น. -->
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>19</integer>
<key>Minute</key>
<integer>0</integer>
</dict>
<key>StandardOutPath</key>
<string>/tmp/dotsync.stdout.log</string>
<key>StandardErrorPath</key>
<string>/tmp/dotsync.stderr.log</string>
</dict>
</plist>-
ระบบ launchd จะสั่งรัน
dot-syncทุกวันเวลา 19:00 น. (หรือทันทีที่ปลุกเครื่องหากเครื่องหลับอยู่) -
ตรวจสอบผลการทำงานย้อนหลังได้ที่:
cat /tmp/dotsync.stdout.log cat /tmp/dotsync.stderr.log
พิมพ์คำสั่งนี้ใน Terminal เพื่อดัมป์และ Push ขึ้น Git ทันที:
dot-syncดึงการตั้งค่าหรือ config ที่เพิ่ง push มาลงเครื่องปัจจุบัน:
chezmoi update- chezmoi จะ pull โค้ดล่าสุด
- อัปเดต Dotfiles (
.zshrc,.gitconfig) - รัน
brew bundleติดตั้งเฉพาะแพ็กเกจของเครื่องนี้ (ถ้าBrewfile.<role>ของเครื่องนี้มีการเปลี่ยนแปลง)
-
วิธีแก้ผ่าน chezmoi:
chezmoi edit ~/.zshrc chezmoi apply chezmoi cd && git commit -am "Update zshrc" && git push origin main && exit
-
วิธีแก้ไฟล์ในเครื่องตรงๆ:
chezmoi re-add ~/.zshrc chezmoi cd && git commit -am "Update zshrc" && git push origin main && exit
# 1. ติดตั้ง Homebrew
/bin/bash -c "$(curl -fsSL [https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh](https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh))"
# 2. ตั้งค่า Homebrew PATH สำหรับ Apple Silicon
eval "$(/opt/homebrew/bin/brew shellenv)"
# 3. ติดตั้ง chezmoi
brew install chezmoichezmoi init --apply <GITHUB_REPO_URL>- พิมพ์เลือกบทบาทของเครื่องนี้:
personalหรือworkแล้วกด Enter - chezmoi จะวางไฟล์ Dotfiles, Binary สคริปต์, Plist และสั่งรัน
brew bundleติดตั้งโปรแกรมของ Role นั้นให้อัตโนมัติ
โหลด Service เข้าสู่ระบบของ macOS:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.dotsync.plist(ทดสอบยิง service ทำงานทันทีด้วย: launchctl kickstart -k gui/$(id -u)/com.user.dotsync)
เปิดดูแอปที่ต้องติดตั้งแบบ Manual:
cat ~/.config/brew/manual-apps.$(chezmoi execute-template '{{ .role }}').txt| คำสั่ง | หน้าที่การทำงาน |
|---|---|
dot-sync |
รัน Dump apps + Pull + Push Git + Apply ครบวงจร |
cz-sync-apps |
ดัมป์ Brewfile และ manual-apps ลง chezmoi source อย่างเดียว |
chezmoi update |
Pull ข้อมูลล่าสุดจาก Git + Apply ลงเครื่องปัจจุบัน |
chezmoi diff |
ดูความต่างระหว่างไฟล์ใน Repo กับไฟล์จริงบนเครื่องก่อน apply |
chezmoi edit-config |
แก้ไข Role ของเครื่องปัจจุบัน (personal หรือ work) |
chezmoi cd |
สลับเข้าสู่โฟลเดอร์ต้นทางของ chezmoi เพื่อจัดการ Git โดยตรง |
launchctl kickstart -k gui/$(id -u)/com.user.dotsync |
สั่งให้ launchd ทำงานทันทีโดยไม่ต้องรอเวลา |
(ทดสอบยิง service ทำงานทันทีด้วย: launchctl kickstart -k gui/$(id -u)/com.user.dotsync)
เปิดดูแอปที่ต้องติดตั้งแบบ Manual:
cat ~/.config/brew/manual-apps.$(chezmoi execute-template '{{ .role }}').txt