from Pixabayfrom Pixabay

本文主要寫給軟體工程師,尤其是後端。

不過,這並不是一篇 yadm 操作教學,而是我在選擇 dotfiles 同步方案時,所做的功課與思路整理,其中的考量大概有下:

  1. 靠自己簡單實作就好,還是要透過工具?
  2. 如果要用工具,工具這麼多,該如何選擇
  3. 工具之間有什麼本質的差別嗎?(其實就是下述流派上的差別)

場景與需求

如〈Python 開發環境設定:zsh、zinit、pyenv、Poetry、Docker〉所言,因為新 VM 的建立,我又得重設一次開發環境,而重設開發環境往往是一個耗時且繁瑣的過程。

在這個過程中,需要重新建立一些設定檔,例如.bashrc.zshrc。這些設定檔通常包含了工具設定、命令別名、環境變數等大量內容,因此特別惱人。

此外,即使不是重建環境,平時要在不同 VM 包括本機電腦間「手動同步」這些檔案,也是一件讓人很想逃避的事。

.zshrc為例,如果它很少變動,那可能還好。但很不幸的,我又是一個很愛為命令列工具建立 alias(別名)的人,光憑這點,就使我不時會修改.zshrc

不同 VM 間的 dotfiles 手動同步讓人想逃避

而當你有 1 台、2 台……甚至更多 VM 時,.zshrc修改後的「內容同步」問題,足以讓你非常痛苦。

以我自己為例,我工作上「只有」2 台 VM,哪怕是兩台,在很長一段時間裡,這兩台 VM 的 alias 設定都沒有完全一致——因為我在其中一台新增了 alias 後,就懶得手動為另一台更新相同內容。

這聽起來有點愚蠢,卻是人之常情……但這次我不忍了!為了解決這個問題,我打算使用「更先進的手段」,來同步和管理這些設定檔。

如此一來,無論「重設開發環境」或「在多個 VM 之間同步設定」,我的 dotfiles 都可以輕鬆保持一致,提高工作效率。

什麼是 dotfiles?

前面已經提了幾次 dotfiles,卻還沒有解釋它。不過相信對於很多人來說,應該一點也不陌生:舉凡在$HOME目錄底下的各種工具設定檔,常常都是以一個點「.」開頭,所以它們被稱為 dotfiles。

當然,它們未必全都放在$HOME目錄底下,甚至也未必皆以「.」開頭,只是在多數時候如此而已。

一些常見的 dotfiles 包括:

  1. .bashrc.bash_profile:最常見的 dotfiles。
  2. .vimrc:Vim 編輯器的設定檔,包含了一些編輯器偏好、快捷鍵綁定等。
  3. .gitconfig:Git 版控系統的設定檔,最基本的功能是儲存使用者的 name 和 email。而我個人也習慣把 Git「子命令」相關的 alias 放在這裡,而非放在.zshrc,像下面這樣:
1
2
3
4
5
6
7
8
9
[user]
name = kyo
email = odinxp@gmail.com

[alias]
st = status
br = branch
co = checkout
brs = branch -a

做過一番功課以後,我認為同步 dotfiles 所使用的手段,大致可分為兩個流派:

  1. Symbolic Link。
  2. Bare Git。

而且各有各的工具方便你使用。

如果想要自己摸索,嘗試,這篇 Reddit 討論串我覺得頗值參考:

我對 dotfiles 管理工具的理解,也大致是從這篇討論延伸而來。

事實上,想要輕鬆同步你的 dotfiles,未必要使用別人寫的工具。最常見的做法,就是透過軟連結(Symbolic Link)。

在此不細論具體的做法為何,可以隨意 Google 一下「symbolic link dotfiles」就有滿坑滿谷的資訊。

意即,自己弄一個 dotfiles repo 並手動建立軟連結,就是一個簡單暴力的方式。

但這樣做的主要缺點是:「軟連結」部分需要你手動建立,也還是不太輕鬆,所以並不推薦使用——但適合不想靠工具,又希望比「複製貼上」更有效的極簡主義者

再「聰明」一點,則是配合 stow,可參考這篇〈【譯】使用 GNU stow 管理你的點文件〉,我想這樣已經足夠優雅了。

方案二:Bare Git

既然如此,那為什麼還需要寫這篇文章呢?當然是為了那些——包括我——不想在本機建立一個獨立的 dotfiles repo 的人!

申言之,軟連結方案通常會改變 dotfiles 的實際存放路徑——因為它們必須集中到 dotfiles repo 底下。而 stow 等工具的通常用途把你手動建立連結部分變成自動。

至於不想要變動 dotfiles 路徑的人(這無疑也是一種偏執呀,哈哈哈!),則需要第二種的「Bare Git」方案。

雖說是第二種方案,但其實兩者都需要在遠端維護一個 dotfiles repo,只不過 Git 方案在「本地」並沒有建立一個獨立的 dotfiles repo——所以也不必變動原來 dotfiles 的存放路徑。

何謂 Bare Git 方案?

具體而言,就是指這篇〈Dotfiles: Best Way to Store in a Bare Git Repository〉中的做法。因為文章就稱它為「Bare Git」,所以我也這麼稱呼。

講白了,就是利用 Git 本身的進階功能(但不是一般我們常用的那種)來達到同步 dotfiles 的目的。

這種做法的特色和優點在於,無須在本機建立額外的 dotfiles repo,而是直接將你的「家目錄」作為 dotfiles repo。此外,你需要主動選擇並加入想要同步的檔案,而不像我們平常使用 Git 時,工作目錄中未被 gitignore 的檔案都會自動被同步。

這篇文章不長,但我實際試著一步步照做後,發現其中的「坑」還真是不少——畢竟這不是我們平常使用 Git 的方式。

經歷一小時的嘗試與挫敗後,我放棄了!決定直接使用工具即可。


同步 dotfiles 的自動化工具選項

管理、同步 dotfiles 究竟有哪些工具可以選擇呢?說真的,非常多!

可以參考這個清單,它依照 GitHub 星星數量排序列出,並附上了言簡意賅的介紹。

如果想要知道工具間的更多細節與比較,則可以參考這個對照表

作為一個 Python 工程師,我偏好選擇由 Python 開發而成的工具。上述頁面中提到的 Dotbotyadm 都是不錯的選項——它們主要都是使用 Python 語言開發的。

我選擇 yadm

老實說,Dotbot 和 yadm 我一開始也不知道要選哪個,所以乾脆直接先挑其中一個來試試,看看稱不稱手、合不合用。

如果是,就可以結束這回合;如果否,就換另一個。

我先試了 yadm,因為已經自己實作過〈Dotfiles: Best Way to Store in a Bare Git Repository〉的內容,我不禁訝異:這不就是自動化的 Bare Git 方案嗎!

流程可以說非常類似,重要的是:它把那些複雜且容易出錯的地方「封裝並隱藏起來了」——顯然這就是我要的!

附帶一提,從 Dotbot 的 GitHub 介紹看來,它更偏向於使用 Symbolic Link:

Dotbot only supports Python 3.8+, and it requires that your account is allowed to create symbolic links.

開始使用 yadm

教學什麼的就不獻醜了,而且步驟也非常簡單,尤其在我親身「折騰」過〈Dotfiles: Best Way to Store in a Bare Git Repository〉以後,更是覺得:靠工具通常還是會讓你輕鬆不少,所以也不再堅持要「自己來」了。

建議直接安裝,並參考官網的「Getting Started」操作。

只要親身實踐過〈Dotfiles: Best Way to Store in a Bare Git Repository〉就會發現:兩者大同小異,只是 yadm 隱藏了更多容易出錯的細節,讓人更容易上手。

安裝好 yadm 後,它就變成了一種「特殊的 Git」指令——但只會影響你的 dotfiles repo。

yadm 常用指令

常用的指令可參考這個頁面

就跟 Git 非常類似——畢竟它本質上就是 Git。只是增加了一些額外的指令方便你查看目前 dotfiles repo 狀態,比如yadm list

這些區別,頁面中也都有說明:

Most of these operations will look like Git commands; because they are. yadm wraps Git, allowing it to perform all of Git’s operations. The difference is your $HOME directory becomes the working directory, and you can run the commands from any directory.

Commands below which are special to yadm are denoted with *, and those which are passed directly through to Git are denoted with git.

所以使用上,幾乎與操作 Git 一致,如下圖:

解說:

  • 我把yadm設 alias 為「y」了。
  • pullpush這些常見 Git 操作,在使用 yadm 時也一樣,所以如果發生「檔案狀態衝突」,也是要依照與 Git 相同方式去處理。
  • 為了滿足同步需求,在遠端(比如 GitHub)還是要建立一個「收集這些 dotfiles 清單與狀態」的倉庫,通常我們也會命名為「dotfiles」。