大家好,我是冯哥的缓存。
上篇建好了自己的Shell 函数库,所有脚本都变得整洁利落。但还有一个问题没解决——换一台机器,所有东西都要重新配一遍。
新机器上:
·~/.bashrc要重新写(或者从旧机器复制)
·~/bin/里的函数库和脚本要重新传过去
·SSH 密钥、Git 配置、vim 配置……每样都要手动弄
如果只有一台电脑,这问题不大。但如果像我一样:
·台式机装桌面版Linux
·笔记本装另一个发行版
·服务器要用命令行操作
·偶尔还要在朋友的电脑上临时用一下
每次重新配环境都要花半天,太浪费生命了。
这一篇,我们就来聊一下怎么解决这个问题——用 dotfiles 管理所有配置文件,换机器一条命令还原全套环境。
💡提示: dotfiles 是 Linux/Unix 下用 Git 管理配置文件的通用做法,几乎所有资深 Linux 用户都有一套自己的 dotfiles。
一、什么是dotfiles
1.1 从"点文件"说起
Linux 下,以 .开头的文件或目录默认是隐藏的(用 ls -a才能看到)。这些文件通常存放用户个人配置:
文件/目录 | 作用 |
~/.bashrc | bash Shell 配置 |
~/.zshrc | zsh Shell 配置 |
~/.vimrc | Vim 编辑器配置 |
~/.gitconfig | Git 全局配置 |
~/.ssh/ | SSH 密钥和配置(敏感,不能随便推到公开仓库) |
~/.config/ | 现代 Linux 应用的配置目录(firefox、VS Code、alacritty 等),应用配置越来越多,是dotfiles管理的重点 |
这些文件加起来,就是这台机器上的"工作环境"。
1.2 dotfiles 管理的核心思路
┌────────────────────────────────────────────────┐
│Git 仓库(dotfiles)│
│┌──────────┐┌──────────┐┌──────────┐│
││ .bashrc││ .vimrc││ .gitconfig││
││ mylib.sh ││ scripts/ ││ .zshrc││
│└──────────┘└──────────┘└──────────┘│
└──────────────────┬─────────────────────────────┘
│ git push
▼
GitHub / Gitee 远程仓库
│ git clone(换机器时)
▼
┌────────────────────────────────────────────────┐
│新机器的 ~/dotfiles/│
│通过软链接或部署脚本,还原到 ~/ 对应位置│
└────────────────────────────────────────────────┘
总结:把配置文件集中到一个 Git 仓库里,换机器时 git clone + 部署,几分钟还原全套环境。
二、方案选择——三种主流做法对比
在开始之前,先看看三种主流方案,选一个适合的:
方案 | 原理 | 优点 | 缺点 | 推荐人群 |
① Git 裸仓库 | 用 git init --bare 直接在 $HOME 建仓库 | 不用软链接,原地管理 | 命令稍复杂,需要别名封装 | 追求极简、不介意复杂命令的用户 |
② GNU stow | 用软链接把 dotfiles/ 里的文件"映射"到 $HOME | 干净、可反向删除、支持批量操作 | 需要额外安装 stow | 大多数人,推荐新手 |
③ 手动软链接 | 自己写脚本,用 ln -s 创建链接 | 完全可控,无依赖 | 需要自己维护脚本 | 想完全控制、不在意维护脚本的用户 |
💡推荐:如果第一次搞 dotfiles,直接用 GNU stow 方案,最省心也最容易理解。下文也以 stow 方案为主讲解。
三、用 GNU stow 管理 dotfiles(推荐方案)
3.1 安装 stow
# Debian/Ubuntu
sudo apt install stow
# Arch
sudo pacman -S stow
# Fedora
sudo dnf install stow
# openSUSE
sudo zypper install stow
验证安装:
stow --version
3.2 建立 dotfiles 目录结构
stow 的核心思想是:在一个目录里按"包"组织配置文件,每个包对应一组软链接。
推荐的目录结构:
~/dotfiles/# Git 仓库根目录
├── bash/# "bash" 包
│└── .bashrc# 实际文件(注意:这里是 .bashrc,不是bashrc)
├── zsh/# "zsh" 包
│└── .zshrc
├── git/# "git" 包
│└── .gitconfig
├── vim/# "vim" 包
│└── .vimrc
├── bin/# "bin" 包(脚本和函数库)
│├── lib/
││└── mylib.sh
│└── scripts/
│└── backup.sh
├── config/# "config" 包(~/.config 下的内容)
│└── alacritty/
│└── alacritty.yml
└── install.sh# 一键部署脚本(换机器时用)
⚠️注意: stow 默认把包目录里的内容"链接到父目录"。所以 bash/包里的 .bashrc,执行 stow bash后会出现在 ~/.bashrc。
3.3 第一次初始化
假设已经有了一套配置,现在要把它纳入 dotfiles 管理:
第一步:创建目录并迁入现有配置
# 创建 dotfiles 目录
mkdir -p ~/dotfiles/bash
cd ~/dotfiles
# 把现有的 .bashrc 移进去(注意路径!)
mv ~/.bashrc ~/dotfiles/bash/
# 创建软链接,让 ~/.bashrc 指向 ~/dotfiles/bash/.bashrc
stow bash
执行完stow bash之后,检查一下:
ls -la ~/.bashrc
# 应该看到:~/.bashrc -> ../dotfiles/bash/.bashrc
💡提示:stow bash的意思是:以当前目录为根,把 bash/ 包里的内容部署到当前目录的上一级(即 $HOME)。因为包里有 .bashrc,所以 ~/.bashrc就被创建了。
第二步:把其他配置也加进来
# Git 配置
mkdir -p ~/dotfiles/git
mv ~/.gitconfig ~/dotfiles/git/
stow git
# vim 配置
mkdir -p ~/dotfiles/vim
mv ~/.vimrc ~/dotfiles/vim/
stow vim
# 函数库和脚本
mkdir -p ~/dotfiles/bin/lib
mkdir -p ~/dotfiles/bin/scripts
# 注意:如果之前按上篇的建议放在 ~/bin/,直接移过来
mv ~/bin/lib ~/dotfiles/bin/
mv ~/bin/scripts ~/dotfiles/bin/
stow bin
第三步:初始化Git 仓库
cd ~/dotfiles
git init
git add .
git commit -m "初始提交:迁入 bash/git/vim/bin 配置"
# 在 GitHub/Gitee 上创建一个名为 dotfiles 的空仓库
git remote add origin https://github.com/用户名/dotfiles.git
git push -u origin main
3.4 日常使用
配置更新后:
# 修改了 ~/.bashrc(实际改的是 ~/dotfiles/bash/.bashrc)
vim ~/dotfiles/bash/.bashrc
# 提交并推送
cd ~/dotfiles
git add .
git commit -m "更新 bashrc:增加新的alias"
git push
在新机器上还原:
# 克隆仓库到 ~/dotfiles
git clone https://github.com/用户名/dotfiles.git ~/dotfiles
cd ~/dotfiles
# 用 stow 部署所有包
stow bash git vim bin
还原全部配置 ✅
💡 **提示:**如果 ~/.bashrc 已经存在(不是之前由 stow 创建的),stow bash 会报错。可以手动备份后删除,或者用 stow --adopt bash 让 stow 接管现有文件(移动成软链接),但不会删除原文件内容。如果原文件有重要内容,--adopt 会安全处理。
四、处理敏感信息
4.1 哪些文件不能推到公开仓库
文件/目录 | 原因 |
~/.ssh/ | 包含私钥,推上去就等于把家门钥匙挂网上 |
~/.gitconfig 里的 user.password | 有些 Git 凭证助手会把密码存在 ~/.gitconfig 或 ~/.git-credentials 或 ~/.config/git/credentials |
~/.aws/ | AWS 密钥 |
任何包含 API Token 的配置文件 | 比如 .vimrc 里的插件管理器 Token |
4.2 安全的做法:模板 + 本地覆盖
思路:把配置文件里的敏感部分抽成"模板",模板推到仓库;本地再建一个"覆盖文件",存真实敏感信息,这个覆盖文件加入 .gitignore。
以.gitconfig为例:
~/dotfiles/git/.gitconfig(推到仓库):
[user]
name = 用户名字
# email 在 ~/.gitconfig_local 里配置(不入库)
[core]
editor = vim
[push]
default = current
~/.gitconfig_local(不推到仓库,存在本地):
[user]
email = 邮箱@example.com
在~/.gitconfig末尾加上:
[include]
path = ~/.gitconfig_local
这样 Git 会同时读取两个文件,_local文件里的配置优先级更高。
把这个文件加入.gitignore:
在~/dotfiles/里创建 .gitignore:
# 本地覆盖文件,不入库
.gitconfig_local
.ssh/
aws/
# 系统自动生成的文件
.DS_Store
4.3 SSH 密钥的处理
SSH 密钥绝对不能推到任何公开仓库。推荐做法:
1.生成新密钥(每台机器独立生成,不要复制私钥):
ssh-keygen -t ed25519 -C "邮箱"
2.公钥可以推到仓库(放在 ~/dotfiles/ssh/公钥.txt里,方便查看):
# 把公钥内容复制到仓库里(不是私钥!)
cat ~/.ssh/id_ed25519.pub > ~/dotfiles/ssh/我的公钥.txt
3.在新机器上重新生成密钥,然后把公钥加到 GitHub/Gitee 的 SSH Keys 设置里。
🚨警告:如果私钥曾经不小心推到了公开仓库,立即更换密钥!去 GitHub/Gitee 上删掉旧的公钥,重新生成一对。
五、写一键部署脚本
换机器时,希望一条命令完成所有操作?在~/dotfiles/里创建一个 install.sh:
#!/bin/bash
# install.sh —— dotfiles 一键部署脚本
# 使用方法:bash install.sh
set -euo pipefail
DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKUP_DIR="$HOME/.dotfiles_backup/$(date +%Y%m%d_%H%M%S)"
print_info(){ echo -e "\033[0;32m[INFO]\033[0m $*"; }
print_warn(){ echo -e "\033[1;33m[WARN]\033[0m $*" >&2; }
print_error() { echo -e "\033[0;31m[ERROR]\033[0m $*" >&2; }
# 检查 stow 是否安装
if ! command -v stow &>/dev/null; then
print_error "stow 未安装,请先安装:sudo apt install stow(或对应发行版的命令)"
exit 1
fi
# 备份已存在的配置文件
backup_file() {
local file="$1"
if [[ -e "$file" ]] && [[ ! -L "$file" ]]; then
mkdir -p "$BACKUP_DIR"
mv"$file""$BACKUP_DIR/"
print_info "已备份:$file -> $BACKUP_DIR/"
fi
}
print_info "开始部署 dotfiles..."
print_info "dotfiles 目录:$DOTFILES_DIR"
# 要部署的包列表(和 ~/dotfiles/ 下的目录名对应)
PACKAGES=("bash""git""vim""bin")
for pkg in"${PACKAGES[@]}"; do
if [[ ! -d "$DOTFILES_DIR/$pkg" ]]; then
print_warn "包 $pkg不存在,跳过"
continue
fi
print_info "部署包:$pkg"
# 备份目标位置已存在的文件(如果它不是软链接)
# stow 会自动处理,但我们先检查一下
find "$DOTFILES_DIR/$pkg" -type f -o -type d | whileread -r src; do
rel="${src#$DOTFILES_DIR/$pkg/}"
dest="$HOME/$rel"
backup_file "$dest"
done
# 用 stow 部署
stow -d "$DOTFILES_DIR" -t "$HOME""$pkg"
print_success "包 $pkg部署完成"
done
# 额外操作:把 ~/bin 加入 PATH(如果还没加的话)
if [[ ":$PATH:" != *":$HOME/bin:"* ]]; then
print_info "请在 ~/.bashrc 末尾加上:"
echo'export PATH="$HOME/bin:$HOME/bin/scripts:$PATH"'
fi
print_success "部署完成!执行 source ~/.bashrc 生效"
保存后在新机器上这样用:
# 新机器上
git clone https://github.com/用户名/dotfiles.git ~/dotfiles
cd ~/dotfiles
bash install.sh
source ~/.bashrc
六、用 Git 裸仓库方案(进阶,可选)
如果不想依赖stow,可以用 Git 裸仓库直接在 $HOME里管理。
初始化:
# 在 $HOME 里建一个裸仓库
git init --bare $HOME/.dotfiles
# 创建一个别名,方便操作
alias dotfiles='/usr/bin/git --git-dir="$HOME/.dotfiles" --work-tree="$HOME"'
# 不让 Git 显示未跟踪的文件(否则 $HOME 里所有文件都会显示)
dotfiles config --local status.showUntrackedFiles no
日常使用:
# 添加文件
dotfiles add ~/.bashrc
dotfiles add ~/.vimrc
dotfiles commit -m "添加 bashrc 和vimrc"
dotfiles push
在新机器上还原:
git clone --bare https://github.com/用户名/dotfiles.git $HOME/.dotfiles
dotfiles checkout
# 如果提示冲突,先把已有的文件备份再checkout
dotfiles checkout 2>&1 | grep -E "^\s+" | xargs -I{} mv {} {}.backup
dotfiles checkout
💡提示:裸仓库方案的好处是不需要 stow,也不需要软链接。但命令比较绕,建议在熟悉 dotfiles 管理之后再尝试。
七、参考别人的dotfiles
不知道自己的dotfiles 该怎么组织?去看看别人是怎么管的。GitHub 上搜索dotfiles能找到几万个仓库,以下是几个高质量的参考:
仓库 | 特点 |
mathiasbynens/dotfiles | 星标最多的 dotfiles 之一,macOS 向,但思路通用 |
holman/dotfiles | 结构很有创意,用 topic/ 目录组织,值得参考思路 |
alrra/dotfiles | 文档写得很好,适合新手参考 |
搜索 dotfiles linux | 能找到很多 Linux 专属的配置 |
💡提示:参考别人的思路,但不要直接 fork 全套。每个人的需求不同,别人的配置里有很多不需要的东西,直接抄反而让环境变复杂。
八、本文速查表
stow 常用命令
命令 | 作用 |
stow bash | 部署 bash/ 包(创建软链接) |
stow -D bash | 删除 bash/ 包的软链接(卸载) |
stow -R bash | 重新部署(先删再建,用于更新) |
stow -n bash | 模拟运行,不实际创建链接(调试用) |
stow -t ~/target bash | 部署到指定目录(而不是父目录) |
dotfiles 目录结构模板
~/dotfiles/
├── bash/.bashrc
├── zsh/.zshrc
├── git/.gitconfig
├── vim/.vimrc
├── bin/lib/mylib.sh
├── bin/scripts/backup.sh
├── install.sh# 一键部署脚本
└── .gitignore# 排除敏感文件
敏感信息检查清单
·~/.ssh/已加入 .gitignore
·~/.gitconfig里没有明文密码(用 _local文件覆盖)
· API Token / 密钥已抽离到不入库的配置文件
·部署脚本里没有硬编码的敏感路径
💡提示:如果怀疑自己不小心把敏感信息推上去了,可以用 git log -p 检查历史记录,或者用 git filter-branch 彻底删除。
现在dotfiles搞定了,换机器不再痛苦。 但还有一个日常操作——远程连接。 SSH 密钥登录、scp 传文件、rsync增量同步、跳板机配置,这些技能使用频率较高。
下篇预告:《Linux SSH 远程连接——密钥免密登录与 scp/rsync 传文件》