tmux 终端工作流完整指南:会话、分屏、自定义快捷键与 iTerm2 配合
如果你经常在终端里写代码、跑服务、看日志、连远程机器,tmux 基本是绕不开的工具。它解决的不是“终端不够漂亮”,而是一个更工程化的问题:终端会话应该像项目状态一样可恢复、可组织、可迁移。
iTerm2 已经是 macOS 上非常强的终端应用,支持标签页、分屏、Hotkey Window、Profile、Trigger、字体主题和快捷键。但 iTerm2 的窗口状态主要活在本机 GUI 里;一旦 SSH 断开、终端关闭、机器重启,很多运行中的上下文就消失了。tmux 则运行在 shell 里面,可以把一个项目的 editor、server、test、log、AI CLI 都放进同一个持久会话。
最推荐的分工是:
iTerm2 = macOS 原生窗口、字体、主题、全局唤起、Profile
tmux = 项目会话、窗口、pane、远程保活、布局恢复
Shell = 命令入口、目录跳转、项目启动脚本
Neovim = 编辑器 split、LSP、搜索、Git、代码修改
这篇文章会按“先能用,再顺手,最后可定制”的顺序介绍 tmux。
一、tmux 到底是什么
tmux 是 terminal multiplexer。直译是“终端复用器”,但更贴近日常使用的理解是:它在一个真实终端里创建多个可持久化的虚拟终端工作区。
它有三层核心对象:
| 对象 | 类比 | 用来做什么 |
|---|---|---|
| session | 一个项目工作区 | frontend、api、blog、prod-ssh |
| window | 工作区里的标签页 | editor、server、test、logs |
| pane | window 里的分屏 | 左边编辑器,右上跑服务,右下看日志 |
用 iTerm2 类比,大概是:
iTerm2 window/tab ≈ 外层项目入口
tmux session ≈ 项目持久工作区
tmux window ≈ 项目内任务标签
tmux pane ≈ 同一任务里的终端分屏
tmux 最关键的能力有四个:
- 断线不丢进程:SSH 断了,tmux 里的服务、日志、编辑器还在。
- 关闭终端不丢现场:detach 后可以随时 attach 回去。
- 统一项目布局:一个 session 里固定 editor/server/test/logs。
- 键盘驱动:通过 prefix 和快捷键快速分屏、切换、复制、重命名。
如果你只在本地写一点脚本,iTerm2 分屏已经够用;如果你有长期项目、远程机器、后台服务、AI CLI、Neovim、日志观察,tmux 的价值会很明显。
二、安装与启动
macOS 推荐用 Homebrew:
brew install tmux
tmux -V
Ubuntu/Debian:
sudo apt update
sudo apt install tmux
tmux -V
Fedora:
sudo dnf install tmux
tmux -V
Arch Linux:
sudo pacman -S tmux
tmux -V
第一次启动:
tmux
这会创建一个匿名 session。更推荐直接给项目命名:
tmux new-session -s idea_visual
常用简写:
tmux new -s idea_visual
tmux ls
tmux attach -t idea_visual
tmux a -t idea_visual
如果 session 不存在就创建,存在就进入:
tmux new-session -A -s idea_visual
这条命令很适合放进 iTerm2 Profile、shell alias 或项目启动脚本。
三、先掌握默认快捷键
tmux 的默认 prefix 是 Ctrl+b。多数操作都不是直接按,而是:
先按 Ctrl+b,松开,再按目标键
常用默认键:
| 操作 | 默认快捷键 |
|---|---|
| detach,离开当前 session | Ctrl+b d |
| 新建 window | Ctrl+b c |
| 下一个 window | Ctrl+b n |
| 上一个 window | Ctrl+b p |
| 按编号切 window | Ctrl+b 0 到 Ctrl+b 9 |
| 重命名 window | Ctrl+b , |
| 关闭当前 pane/window | exit 或 Ctrl+d |
| 左右分屏 | Ctrl+b % |
| 上下分屏 | Ctrl+b " |
| 在 pane 间切换 | Ctrl+b o |
| 显示 pane 编号并跳转 | Ctrl+b q 后按编号 |
| 当前 pane 全屏/还原 | Ctrl+b z |
| 进入复制模式 | Ctrl+b [ |
| 粘贴 tmux buffer | Ctrl+b ] |
| 命令行模式 | Ctrl+b : |
刚开始不需要记全。先记住这几个就能工作:
Ctrl+b d 离开但不关闭
tmux a 回来
Ctrl+b c 新建 window
Ctrl+b % 左右分屏
Ctrl+b " 上下分屏
Ctrl+b z 当前 pane 全屏
Ctrl+b [ 复制模式
四、session:把项目工作区保留下来
1. 创建、进入、离开
创建一个项目 session:
tmux new -s blog
离开 session:
Ctrl+b d
列出所有 session:
tmux ls
重新进入:
tmux attach -t blog
创建或进入同名 session:
tmux new -A -s blog
2. 重命名与删除
重命名当前 session:
Ctrl+b $
从外部重命名:
tmux rename-session -t old-name new-name
删除一个 session:
tmux kill-session -t blog
删除所有 session:
tmux kill-server
kill-server 会终止 tmux 管理的全部会话,谨慎使用。
3. 推荐命名策略
session 名字不要太抽象。建议直接用项目名或机器名:
idea_visual
api-server
web-console
prod-bastion
staging-k8s
如果你同时做多个分支实验,可以把分支或任务加进去:
blog-main
blog-tmux-post
api-auth-refactor
五、window:给项目任务分层
tmux window 适合放“同一项目里的不同任务”。例如:
0 editor
1 server
2 test
3 logs
4 git
常用操作:
| 操作 | 默认键 |
|---|---|
| 新建 window | Ctrl+b c |
| 重命名 window | Ctrl+b , |
| 下一个 window | Ctrl+b n |
| 上一个 window | Ctrl+b p |
| 按编号切换 | Ctrl+b 0..9 |
| 显示 window 列表 | Ctrl+b w |
| 关闭当前 window | 退出所有 pane 或 Ctrl+b & |
从命令行创建具名 window:
tmux new-window -n server
tmux new-window -n test
tmux new-window -n logs
在脚本里创建一个简单布局:
tmux new-session -d -s blog -n editor -c "$PWD"
tmux send-keys -t blog:editor "nvim" C-m
tmux new-window -t blog -n server -c "$PWD"
tmux send-keys -t blog:server "npm run start" C-m
tmux new-window -t blog -n git -c "$PWD"
tmux attach -t blog
这里的 -d 表示后台创建,-c "$PWD" 表示窗口从当前目录启动。
六、pane:把同一个任务拆成可观察区域
pane 是 tmux 里最常用的能力。典型布局:
┌─────────────────────────────┬──────────────────────┐
│ │ npm run start │
│ nvim ├──────────────────────┤
│ │ npm run typecheck │
└─────────────────────────────┴──────────────────────┘
默认分屏:
Ctrl+b % 左右分屏
Ctrl+b " 上下分屏
Ctrl+b z 当前 pane 全屏/还原
Ctrl+b x 关闭当前 pane
Ctrl+b q 显示 pane 编号
这里有一个容易误解的地方:tmux 文档里的 split-window -h 和 split-window -v 是按拆分方向命名的。-h 表示 horizontal split,结果是生成左右两个 pane;-v 表示 vertical split,结果是生成上下两个 pane。很多 GUI 终端会按分隔线方向描述“垂直/水平分屏”,所以看起来像是反的。日常记忆可以更直接:
split-window -h 左右分屏
split-window -v 上下分屏
调整布局:
Ctrl+b Space 在内置布局间切换
Ctrl+b { 当前 pane 向前交换
Ctrl+b } 当前 pane 向后交换
Ctrl+b ! 把当前 pane 拆成独立 window
默认 pane 切换是 prefix 后再按方向键。很多人会改成 Vim 风格:
Ctrl+h 左
Ctrl+j 下
Ctrl+k 上
Ctrl+l 右
这组键也是 tmux 与 Neovim 配合的关键,后面会给完整配置。
七、复制模式:不用鼠标也能翻历史、复制文本
tmux 每个 pane 都有自己的 scrollback。默认进入复制模式:
Ctrl+b [
如果配置了 Vi 模式,就可以用:
h/j/k/l 移动
Ctrl+u 上翻半页
Ctrl+d 下翻半页
g 到顶部
G 到底部
/ 搜索
n 下一个匹配
N 上一个匹配
Space 开始选择
Enter 复制选中内容
q 退出复制模式
推荐把复制模式改成 Vi 风格,并用 v 开始选择、y 复制:
setw -g mode-keys vi
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind-key -T copy-mode-vi Escape send-keys -X cancel
macOS 上如果想复制到系统剪贴板,可以用 reattach-to-user-namespace 或更现代的 OSC 52。简单起步可以先交给终端鼠标复制;等习惯 tmux 后再加 tmux-yank 插件。
八、.tmux.conf:把默认配置改成顺手的配置
tmux 配置文件通常是:
~/.tmux.conf
修改后在 tmux 里执行:
Ctrl+b :source-file ~/.tmux.conf
更常见的做法是绑定一个 reload 快捷键:
bind r source-file ~/.tmux.conf \; display-message "tmux config reloaded"
以后按:
Ctrl+b r
就能重新加载配置。
1. 一份可直接使用的基础配置
下面这份配置适合 macOS + iTerm2 + Neovim 用户作为起点:
# Use 256 colors and truecolor when terminal supports it.
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",xterm-256color:RGB"
# Make tmux feel more responsive.
set -sg escape-time 10
set -g focus-events on
# History.
set -g history-limit 50000
# Start window and pane numbering at 1.
set -g base-index 1
setw -g pane-base-index 1
set -g renumber-windows on
# Mouse support: select pane/window, resize pane, scroll history.
set -g mouse on
# Vi-style copy mode.
setw -g mode-keys vi
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind-key -T copy-mode-vi Escape send-keys -X cancel
# Reload config.
bind r source-file ~/.tmux.conf \; display-message "tmux config reloaded"
# Easier splits. Keep the current path when splitting.
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Create windows in the current path.
bind c new-window -c "#{pane_current_path}"
# Vim-style pane movement with prefix.
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Resize panes with repeated prefix bindings.
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# Quickly maximize the current pane.
bind m resize-pane -Z
# Clear scrollback and screen.
bind C-l send-keys C-l \; clear-history
# A readable status line.
set -g status-position bottom
set -g status-interval 5
set -g status-left-length 40
set -g status-right-length 120
set -g status-left "#[bold] #S #[default]"
set -g status-right "#{pane_current_path} | %Y-%m-%d %H:%M "
set -g window-status-current-format "#[bold] #I:#W "
set -g window-status-format " #I:#W "
这份配置做了几件重要的事:
mouse on让滚动、选择 pane、调整大小更自然;base-index 1让 window 编号从 1 开始,更贴近键盘数字;split-window -c "#{pane_current_path}"让新 pane 继承当前目录;|和-比默认的%、"更容易记;h/j/k/l和H/J/K/L形成移动与 resize 的对应关系;- status line 保持克制,只显示 session、window、路径和时间。
2. 是否要把 prefix 从 Ctrl+b 改成 Ctrl+a
很多人会把 prefix 改成 Ctrl+a:
unbind C-b
set -g prefix C-a
bind C-a send-prefix
优点:
Ctrl+a更靠近左手小指,按起来更快;- 如果你以前用过 GNU screen,会更熟悉;
- tmux 高频使用时手感更轻。
代价:
- shell 里
Ctrl+a默认是移动到行首; - Readline、Zsh、Bash、Emacs 用户可能会觉得冲突;
- 远程机器和默认环境不一致时容易按错。
我的建议:
刚开始:保留 Ctrl+b
高频使用后:再考虑 Ctrl+a
已经习惯 shell 的 Ctrl+a 行首跳转:不要改
如果改成 Ctrl+a,最好给 shell 行首动作留一个替代键,例如在 Zsh/Bash 里继续使用 Home 或 Ctrl+x Ctrl+a,否则你会把终端编辑体验弄乱。
九、快捷键绑定的设计原则
tmux 的快捷键不要只是“能绑定就绑定”。更好的做法是按层级设计。
1. 保留三层边界
Neovim 内部移动: Ctrl+h/j/k/l
tmux 项目内移动: Ctrl+h/j/k/l 或 prefix + h/j/k/l
iTerm2 外层切换: Cmd+Number、Cmd+Option+Number、Cmd+Arrow
不要把 iTerm2、tmux、Neovim 全部改成同一套 prefix。短期看统一,长期会混乱。更稳定的模型是:
| 层级 | 负责范围 | 推荐键 |
|---|---|---|
| Neovim | 编辑器 split/window | Ctrl+h/j/k/l |
| tmux | 同一项目内的 pane/window | Ctrl+h/j/k/l、prefix |
| iTerm2 | 不同项目、不同机器、临时终端 | Cmd 系列 |
| macOS | 应用切换 | Cmd+Tab |
2. 常用操作直接绑定,危险操作保留 prefix
适合无 prefix 直接绑定:
pane 方向切换
少量 resize
复制模式里的 v/y
不建议无 prefix 直接绑定:
kill-pane
kill-session
rename-window
new-session
source-file
原因很简单:移动是高频、低风险;关闭和重命名是低频、高风险。
3. 把键位设计成可推理
推荐:
h/j/k/l 移动 pane
H/J/K/L 调整 pane 大小
| 左右分屏
- 上下分屏
r reload
m maximize
不推荐:
a 打开日志
g resize
u reload
x 新建 window
快捷键不是越短越好,而是要看半年后你还能不能猜出来。
十、Neovim 与 tmux:统一 pane/split 移动
如果你在 Neovim 里也使用 split,最烦的是边界切换:
Neovim split 内部:Ctrl+w h/j/k/l
tmux pane 之间: prefix h/j/k/l
更好的方案是用 vim-tmux-navigator,让 Ctrl+h/j/k/l 同时理解 Neovim split 和 tmux pane。
Neovim lazy.nvim 配置:
return {
{
"christoomey/vim-tmux-navigator",
cmd = {
"TmuxNavigateLeft",
"TmuxNavigateDown",
"TmuxNavigateUp",
"TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<C-h>", "<cmd><C-U>TmuxNavigateLeft<cr>", desc = "Move left across nvim/tmux" },
{ "<C-j>", "<cmd><C-U>TmuxNavigateDown<cr>", desc = "Move down across nvim/tmux" },
{ "<C-k>", "<cmd><C-U>TmuxNavigateUp<cr>", desc = "Move up across nvim/tmux" },
{ "<C-l>", "<cmd><C-U>TmuxNavigateRight<cr>", desc = "Move right across nvim/tmux" },
{ "<C-\\>", "<cmd><C-U>TmuxNavigatePrevious<cr>", desc = "Move to previous nvim/tmux pane" },
},
},
}
对应 .tmux.conf:
# Smart pane switching with awareness of Vim/Neovim splits.
vim_pattern='(\S+/)?g?\.?(view|l?n?vim?x?|fzf)(diff)?(-wrapped)?'
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +${vim_pattern}$'"
bind-key -n C-h if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
bind-key -n C-j if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
bind-key -n C-k if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
bind-key -n C-l if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
bind-key -n C-\\ if-shell "$is_vim" 'send-keys C-\\' 'select-pane -l'
bind-key -T copy-mode-vi C-h select-pane -L
bind-key -T copy-mode-vi C-j select-pane -D
bind-key -T copy-mode-vi C-k select-pane -U
bind-key -T copy-mode-vi C-l select-pane -R
bind-key -T copy-mode-vi C-\\ select-pane -l
这样以后:
Ctrl+h/j/k/l
在 Neovim split 内会移动 Neovim window;到达边界后会继续移动到 tmux pane。这个体验非常接近一个统一 IDE。
注意:如果使用 vim-tmux-navigator,不要再同时保留普通的 Neovim Ctrl+h/j/k/l window 映射,否则同一组按键会互相覆盖。
十一、iTerm2 怎么和 tmux 配合更方便
iTerm2 和 tmux 不是二选一。关键是不要让它们抢同一层职责。
1. iTerm2 负责外层项目入口
iTerm2 保留原生快捷键:
| 场景 | 推荐 iTerm2 快捷键 |
|---|---|
| 新建 tab | Cmd+T |
| 关闭 tab/window | Cmd+W |
| tab 间切换 | Cmd+Left/Right 或 Cmd+Number |
| window 间切换 | Cmd+Option+Number |
| 临时 iTerm2 垂直分屏 | Cmd+D |
| 临时 iTerm2 水平分屏 | Cmd+Shift+D |
| iTerm2 pane 间切换 | Cmd+Option+Arrow 或 Cmd+[ / Cmd+] |
| 最大化当前 iTerm2 pane | Cmd+Shift+Enter |
| 全局唤起终端 | Hotkey Window |
tmux 负责项目内部:
一个项目里的 editor/server/test/logs:tmux pane/window
不同项目或不同机器:iTerm2 tab/window
临时一次性命令:iTerm2 split 或新 tab
这样最稳定:
Ctrl系列交给 shell/tmux/Neovim;Cmd系列交给 iTerm2/macOS;- 不要让 iTerm2 抢
Ctrl+h/j/k/l; - 不要把 tmux prefix 绑定成
Cmd组合键。
2. 用 Profile 自动进入 tmux
在 iTerm2 里可以为常用项目创建 Profile:
iTerm2 Preferences
-> Profiles
-> +
-> General
-> Command: Command
填入:
cd ~/project/ai_project/idea_visual && tmux new-session -A -s idea_visual
以后从这个 Profile 打开的 tab 会自动进入项目目录并 attach 到同名 tmux session。
也可以创建一个通用 shell 函数:
workon() {
if [ -z "$1" ]; then
echo "usage: workon <project-dir-name>"
return 1
fi
local dir="$HOME/project/$1"
if [ ! -d "$dir" ]; then
echo "directory not found: $dir"
return 1
fi
cd "$dir" || return
tmux new-session -A -s "$1"
}
使用:
workon idea_visual
workon api-server
workon frontend-app
如果你的项目路径不统一,可以用更直接的函数:
tmux_here() {
local name
name="$(basename "$PWD" | tr '.:' '__')"
tmux new-session -A -s "$name"
}
进入项目目录后:
tmux_here
3. Hotkey Window + tmux 是一个很舒服的组合
iTerm2 的 Hotkey Window 适合做“随叫随到”的终端入口。建议设置成:
Profile: hotkey
Command: tmux new-session -A -s scratch
Window: floating / full width / top or center
这样你可以随时唤起一个 scratch tmux session:
- 临时跑命令;
- 记录短任务;
- SSH 到机器检查状态;
- 打开一个长期保留的 REPL;
- 放一个常驻 AI CLI。
注意:Hotkey Window 里的 tmux session 不要和长期项目 session 混在一起。scratch 就做临时任务,项目仍然用项目名 session。
4. iTerm2 的外观层:Nerd Font + Oh My Posh
iTerm2 的外观不要只理解成配色。真正影响日常可读性的,是字体、图标、prompt 信息密度和 tmux status line 是否协调。
如果你想把 shell prompt 做得更现代,可以用 Oh My Posh themes 作为主题选择入口。Oh My Posh 官方提供了大量内置主题,完整列表可以从主题页跳到 GitHub 查看;带 minimal 的主题通常不依赖 Nerd Font,其他大量主题会使用图标,所以更推荐先配置 Nerd Font。
macOS + iTerm2 的基础步骤:
brew install jandedobbeleer/oh-my-posh/oh-my-posh
oh-my-posh font install meslo
然后到 iTerm2 里把 Profile 字体改成安装好的 Nerd Font:
iTerm2 Preferences
-> Profiles
-> Text
-> Font
如果你更喜欢和我的 dotfiles 保持一致,可以用 Hack Nerd Font Mono。我的 dotfiles 里也提供了修复终端字体的脚本,目标字体名是 HackNFM-Regular 12,用于解决 NvChad 图标或终端图标显示成 ? 的问题。
Zsh 中启用 Oh My Posh 的方式是把 init 放到 ~/.zshrc 末尾:
eval "$(oh-my-posh init zsh)"
如果要指定主题,可以先从主题页挑一个名字,例如 catppuccin、tokyo、powerlevel10k_modern、pure,再写成:
eval "$(oh-my-posh init zsh --config catppuccin)"
更稳的做法是把主题导出成本地配置,避免每次 shell 启动时依赖远端主题解析:
mkdir -p ~/.config/oh-my-posh
oh-my-posh config export --config catppuccin --output ~/.config/oh-my-posh/catppuccin.omp.json
eval "$(oh-my-posh init zsh --config ~/.config/oh-my-posh/catppuccin.omp.json)"
如果你已经在用 Oh My Zsh,建议把 ZSH_THEME 设为空或保留一个很轻的主题,然后让 Oh My Posh 作为最后的 prompt 渲染层:
ZSH_THEME=""
source $ZSH/oh-my-zsh.sh
eval "$(oh-my-posh init zsh --config ~/.config/oh-my-posh/catppuccin.omp.json)"
在 iTerm2 + tmux 组合里,我建议把信息分成两层:
| 层级 | 放什么信息 | 不建议放什么 |
|---|---|---|
| Oh My Posh prompt | 当前目录、Git branch、Git dirty 状态、语言版本、命令耗时 | 太长的 Kubernetes/context 信息 |
| tmux status line | session、window、pane path、时间、少量运行状态 | 和 prompt 重复的 Git branch |
也就是说,prompt 关注“当前命令上下文”,tmux status line 关注“当前工作区上下文”。两边都显示同一组信息,会浪费横向空间。
5. 用我的 dotfiles 复现这套工作流
我的个人配置放在 RainLib/dotfiles。这个仓库用 chezmoi 管理 dotfiles,覆盖 zsh、Neovim、tmux、WezTerm、Kitty、Ghostty、Alacritty 等终端和编辑器配置。
新机器上可以这样初始化:
brew install chezmoi
chezmoi init https://github.com/RainLib/dotfiles.git
chezmoi apply -v
也可以一步完成:
chezmoi init --apply https://github.com/RainLib/dotfiles.git
这个 dotfiles 里和 iTerm2/tmux 最相关的点是:
- macOS 脚本会安装 iTerm2、tmux、TPM、Nerd Fonts 等依赖;
- tmux 主配置来自
dot_tmux.conf,实际落地为~/.tmux.conf; - tmux prefix 使用
Ctrl+s,不是默认的Ctrl+b; - tmux 插件包含
tmux-plugins/tpm、catppuccin/tmux、christoomey/vim-tmux-navigator; - Neovim 和 tmux 都使用
vim-tmux-navigator,所以Ctrl+h/j/k/l可以跨 Neovim split 和 tmux pane 移动; scripts/fix-terminal-fonts.sh可以修复 iTerm2 字体,避免 Nerd Font 图标显示异常。
如果只想应用 tmux 和 Neovim 的相关配置,可以从 dotfiles 仓库根目录执行:
sh scripts/apply.sh ~/.tmux.conf ~/.config/nvim
tmux source-file ~/.tmux.conf
然后检查 tmux prefix 和跨 pane 绑定:
tmux show -g prefix
tmux list-keys -T root C-h
期望结果是:
prefix C-s
C-h 绑定到 if-shell ... select-pane -L
当前 dot_zshrc 使用的是 Oh My Zsh 主题 mgutz,并保留了 starship 初始化的注释。如果你想切到 Oh My Posh,就把上面 Oh My Posh 初始化放到 dot_zshrc 末尾,再通过 chezmoi apply 下发:
chezmoi cd
# 编辑 dot_zshrc
chezmoi apply -v ~/.zshrc
exec zsh
这样做的好处是:iTerm2 的字体、tmux 的 pane 导航、Neovim 的 split 导航、Zsh prompt 主题都放回 dotfiles 管理,不会散落在不同机器的手工设置里。
6. iTerm2 的 tmux Integration:什么时候用 tmux -CC
iTerm2 支持 tmux Control Mode,可以用原生 iTerm2 tab/window/pane 显示 tmux 会话:
tmux -CC new -A -s idea_visual
或进入已有 session:
tmux -CC attach -t idea_visual
优点:
- tmux window 可以映射成 iTerm2 tab/window;
- 可以用更多 iTerm2 原生 UI;
- 对喜欢 GUI tab 的用户更自然。
代价:
- 行为和普通 tmux 有差异;
- 跨机器、跨终端迁移时不如普通 tmux 直观;
- 排查问题时要区分普通 tmux 与 iTerm2 Control Mode;
- 部分 tmux 插件、状态栏、复制体验可能需要额外适配。
我的建议:
刚建立稳定工作流:用普通 tmux
已经熟悉 tmux 后:再试 tmux -CC
经常 SSH 到 Linux 服务器:优先普通 tmux
主要本机 macOS 开发,喜欢 iTerm2 原生 tab:可以试 tmux -CC
普通 tmux 的迁移性更好,tmux -CC 更像 iTerm2 用户的增强模式。
十二、插件:少装,但装对
tmux 不需要一上来装很多插件。先把原生能力用顺,再考虑插件。
常见插件:
| 插件 | 作用 | 是否推荐 |
|---|---|---|
tmux-plugins/tpm | tmux plugin manager | 需要插件时再装 |
tmux-plugins/tmux-sensible | 一组合理默认值 | 可选 |
tmux-plugins/tmux-yank | 复制到系统剪贴板 | macOS 常用 |
tmux-plugins/tmux-resurrect | 保存/恢复 session 布局 | 长期工作区推荐 |
tmux-plugins/tmux-continuum | 自动保存/恢复 | 谨慎使用 |
christoomey/vim-tmux-navigator | Neovim/tmux pane 无缝切换 | Neovim 用户强烈推荐 |
TPM 安装方式:
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
.tmux.conf 中加入:
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-yank'
set -g @plugin 'tmux-plugins/tmux-resurrect'
run '~/.tmux/plugins/tpm/tpm'
重新加载配置后,在 tmux 里按:
Ctrl+b I
安装插件。
我的取舍建议:
只想稳定工作:不装插件也可以
需要系统剪贴板:tmux-yank
需要恢复布局:tmux-resurrect
Neovim 重度用户:vim-tmux-navigator
不想维护复杂状态:暂时别上 continuum
十三、推荐工作区布局
1. 普通 Web 项目
session: idea_visual
window 1: editor
pane 1: nvim
pane 2: npm run start
pane 3: npm run typecheck
window 2: git
pane 1: git status / lazygit
window 3: logs
pane 1: server logs
可以用命令创建:
session="idea_visual"
tmux new-session -d -s "$session" -n editor -c "$PWD"
editor_pane="$(tmux display-message -p -t "$session:editor" "#{pane_id}")"
tmux send-keys -t "$editor_pane" "nvim" C-m
server_pane="$(tmux split-window -h -t "$editor_pane" -c "$PWD" -P -F "#{pane_id}")"
tmux send-keys -t "$server_pane" "npm run start" C-m
test_pane="$(tmux split-window -v -t "$server_pane" -c "$PWD" -P -F "#{pane_id}")"
tmux send-keys -t "$test_pane" "npm run typecheck" C-m
tmux select-pane -t "$editor_pane"
tmux new-window -t "$session" -n git -c "$PWD"
tmux send-keys -t "$session:git" "git status" C-m
tmux attach -t "$session"
这里用 #{pane_id} 捕获真实 pane ID,而不是写死 editor.1、editor.2、editor.3。这样无论你的 pane-base-index 是默认的 0,还是前面配置里的 1,脚本都能正常运行。
2. AI Coding 工作区
如果你用 Codex CLI、Claude Code CLI 或其他终端 Agent,建议给它独立 pane:
┌──────────────────────────────┬──────────────────────────────┐
│ │ codex / claude │
│ nvim │ │
│ ├──────────────────────────────┤
│ │ npm test / npm run build │
└──────────────────────────────┴──────────────────────────────┘
原因:
- AI CLI 输出很长,独立 pane 更容易观察;
- 修改文件后可以立刻在 Neovim 里 review;
- 测试 pane 可以持续跑验证命令;
- tmux session 可以保留 AI CLI 的上下文和日志。
3. 远程服务器工作区
远程机器上尤其适合 tmux:
ssh user@server
tmux new -A -s ops
建议在远程 session 里分 window:
1 shell
2 logs
3 docker
4 k8s
5 db
远程机器上不要太依赖 iTerm2 专有能力,因为你可能从不同终端进入。tmux 原生命令和 .tmux.conf 才是最可迁移的部分。
十四、常见问题
1. 为什么 tmux 里颜色不对
先检查外层终端:
echo $TERM
iTerm2 通常是 xterm-256color。tmux 里可以配置:
set -g default-terminal "screen-256color"
set -ga terminal-overrides ",xterm-256color:RGB"
如果你的 Neovim 主题需要 truecolor,再确认:
:set termguicolors?
2. 为什么 Esc 或 Vim 模式有延迟
加入:
set -sg escape-time 10
默认 escape-time 偏保守,会让 Vim/Neovim 用户感觉 Esc 反应慢。
3. 为什么新 pane 没有在当前目录打开
split 绑定里要加 -c "#{pane_current_path}":
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
bind c new-window -c "#{pane_current_path}"
4. 鼠标滚动进入了 shell 历史而不是 tmux 历史
开启 mouse:
set -g mouse on
然后滚动时 tmux 会进入 pane 的 scrollback。需要复制时,可以用 tmux copy mode,也可以按住 Option 绕过 tmux 让 iTerm2 直接选择文本。
5. SSH 断开后怎么恢复
重新 SSH,再 attach:
ssh user@server
tmux ls
tmux attach -t ops
如果你之前只是 detach 或网络断开,进程仍然在 session 里。
6. 什么时候不用 tmux
下面这些场景 iTerm2 原生能力就够:
- 只是临时跑一条命令;
- 只需要本机短期 split;
- 不需要保留工作现场;
- 不使用 SSH;
- 项目没有长期运行的服务、日志、测试。
tmux 的价值来自“持久工作区”。如果没有持久化需求,不必强行套一层。
十五、最终推荐配置
如果你想快速落地,可以按这个顺序:
- 安装 tmux。
- 使用
tmux new -A -s project-name管理每个项目。 - 保留 iTerm2 的
Cmd系列快捷键,别让它抢 tmux/Neovim 的Ctrl系列。 - 在
.tmux.conf开启 mouse、Vi copy mode、当前目录分屏。 - 把分屏改成
|和-。 - 用
h/j/k/l做 pane 移动,H/J/K/L做 resize。 - 如果用 Neovim,安装
vim-tmux-navigator,统一Ctrl+h/j/k/l。 - 高频项目用 iTerm2 Profile 自动执行
cd project && tmux new -A -s project。 - 给 iTerm2 配好 Nerd Font,再按需接入 Oh My Posh themes。
- 用 dotfiles/chezmoi 管理
~/.zshrc、~/.tmux.conf和~/.config/nvim,避免多台机器配置漂移。 - 需要恢复布局时再引入
tmux-resurrect。
最小可用命令只有三条:
tmux new -A -s idea_visual
tmux ls
tmux attach -t idea_visual
最核心的心智模型也只有一句:
iTerm2 管外层入口,tmux 管项目现场,Neovim 管代码编辑。
把这条边界守住,终端工作流会稳定很多。