第 5 章 使用 tmux 结对编程

到目前为止,我们已经学习了日常使用 tmux 以及修改配置。而 tmux 最受开发人员欢迎的功能之一就是结对编程。那是我第一次使用 tmux,当我的朋友向我介绍 tmux 的众多功能时我立刻就喜欢上了这个功能。

结对编程有很多好处。和其他开发人员一起工作能够帮你发现许多你无法自己看到的事情,除非你们身处同一位置,否则结对编程就会变得相当困难。使用例如 iChat,Skype 甚至是 GoToMeeting 这种屏幕共享的软件会占用相当多的带宽,而且在网络状况不好时就会变得非常糟糕。在本章,我们会学习使用 tmux 进行结对编程,之后你就可以和另一位开发人员一起远程工作了,甚至可以使用糟糕的宾馆 WiFi 网络。

和远程用户协作有两种方式。第一种方式需要创建一个新的用户账户,你和他人一起共享这个账户。在这个账户下配置 tmux 和开发环境,然后把它作为一个共享的工作空间。第二种办法是使用 tmux 的 sockets 连接,这样你就可以让第二个用户连接到你的 tmux 会话中而无需共享你的账户信息。

这两种方法都有一种固有的安全缺陷:它们能让他人看到你的屏幕信息和你的账户。你可能在放任某人任意查看你的文件。要解决这个问题,最好使用一个中间服务器来进行结对编程。使用一个便宜的 VPS 或是一个用 VirtualBox(链接)或 Vagrant(链接)创建的虚拟机,你可以快速地创建一个用于结对编程的开发环境。在本章,我们会学习在远程服务器上分别使用这两种进行结对编程。

5.1 使用共享账户结对编程

使用共享账户是和他人共同协作的最简便的方式。在一个 nutshell 里,你可以开启机器上的 SSH 访问权限,将它作为主机,然后在机器上安装并配置 tmux,之后再创建一个 tmux 会话。第二个用户可以使用相同的账户登录到这台机器里然后连接到刚才创建的 tmux 会话中。通过使用 SSH 公开密钥,可以让登录过程变得透明化。下面我们来讨论这个过程。假设我们在使用一台名为 puzzles 的服务器,它使用 Ubuntu 操作系统并且已经安装了 SSH 后台程序。

首先,在服务器上创建一个名为 tmux 的用户账户。这个账户专门用于结对操作。

tmux@puzzles$ adduser tmux

使用新创建的账户前,需要配置这个账户让它添加其他开发人员的 SSH 密钥,这样他们就可以通过这些密钥来登录这个账户。可以在 tmux 账户下创建 ~/.ssh/authorized_keys 文件来完成这个操作。首先使用 su 命令切换到 tmux 账户:

tmux@puzzles$ su tmux

然后要创建 .ssh 目录和 .ssh/authorized_keys 文件,并为它们配置相应的文件权限。确保只有 tmux 这个用户可以读、写或执行这些文件。命令如下:

tmux@puzzles$ mkdir ~/.ssh
tmux@puzzles$ touch ~/.ssh/authorized_keys
tmux@puzzles$ chmod 700 ~/.ssh
tmux@puzzles$ chmod 600 ~/.ssh/authorized_keys

接下来,就可以把公钥传输到这台服务器上了。在桌面工作机上,生成本机的公钥然后上传到服务器:

$ scp -p id_rsa.pub tmux@puzzles.local

然后在服务器上,把公钥添加到 authorized_keys 里。

tmux@puzzles$ cat id_rsa.pub >> ~/.ssh/authorized_keys

其他需要这个共享账户登录到服务器上的所有人都要重复上述过程。

从这里开始,我们来配置 tmux,文本编辑器,编译器,编程需要和版本控制系统,就像在其他开发环境要做的那样。然后在服务器上创建一个新的 tmux 会话。

tmux@puzzles$ tmux new-session -s Pairing

团队中的其他成员可以登录到服务器上然后通过以下命令连接到这个会话中:

tmux@puzzles$ tmux attach -t Pairing

然后就可以在同一个项目里共同协作了。当然,我们可以从会话中分离出来在后来再重新连接到这个会话,也就是说可以让开发环境一次就运行数天甚至数周。这样只要有一个支持 SSH 的终端就可以在任何时间、任何地点都能连接到这个开发环境了。

5.2 使用共享账号和组会话

当两个人连接到同一个 tmux 会话时,他们通常会看到相同的内容并在同一个窗口里交互。但是很多时候人们希望能够在独立的、不同的窗口工作而不用被完全控制。

使用“组会话(grouped session)”可以实现这个功能。下面我们来演示一下,首先先在远程服务器上创建一个新的会话叫做 groupedsession。

tmux@puzzles$ tmux new-session -s groupedsession

然后,另一个用户不去连接到这个会话,而是通过“创建一个新的会话”来加入到这个会话里,他需要指定原始会话 groupedsession,然后再指定一个他或她自己的会话名,就像这样:

tmux@puzzles$ tmux new-session -t groupedsession -s mysession

当第二个会话启动时,两个用户都可以同时在这个会话里进行交互,就像是第二个用户已经连接到这个会话一样。但是,每个用户可以创建相互独立的窗口。因此,如果新用户创建了一个窗口,都会在状态栏里看到新的窗口出现了,但是用户仍然会处于当前工作的窗口!这对那些“嘿,我有个想法我先去试试”的时刻特别适合,或者有时候有人想用 Emacs 而有人想用 Vim 的时候也很合适,就像图13(两个用户共享同一个会话)所示的那样。

图13 - 两个用户共享同一个会话 图13 - 两个用户共享同一个会话

第二个用户可以使用 kill-session 命令杀死他或她的会话,而原始会话依然会存在。但是,如果所有的窗口都关闭的话那么这两个会话都会被杀死。

使用共享账户和 tmux 是结对编程最简单的方式,但是有时候我们并不是总是愿意和团队成员共享账号。下面我们来看看另一种方式。

5.3 使用独立账户和 Socket 结对编程

使用 tmux 提供的 socket 支持,可以创建让多个用户非常容易连接的 tmux 会话。

首先,我们创建两个新的用户账号:一个名为 ted,另一个名为 barney。

tmux@puzzles$ sudo adduser ted
tmux@puzzles$ sudo adduser barney

接下来,创建“tmux”分组以及 /var/tmux 文件夹用来保存共享会话。

tmux@puzzles$ sudo groupadd tmux
tmux@puzzles$ sudo mkdir /var/tmux

要更改 /var/tmux 目录的组权限,这样 tmux 组就能访问它了:

tmux@puzzles$ sudo chgrp tmux /var/tmux

然后修改文件夹的权限让新的文件都能被所有的 tmux 组内用户访问:

tmux@puzzles$ sudo chmod g+ws /var/tmux

最后,添加 Ted 和 Barney 用户到 tmux 组内。

tmux@puzzles$ sudo usermod -aG tmux ted
tmux@puzzles$ sudo usermod -aG tmux barney

创建并共享会话

之前,我们已经使用过 new-session 命令来创建会话,但是那会使用默认的 socket 位置,我们是无法对它进行操作的。因此我们在这里不会创建命名会话,而是通过 -S 参数来创建我们自己的会话。

我们先登录 ted 账户然后使用 socket 创建一个新的 tmux 会话:

ted@puzzles$ tmux -S /var/tmux/pairing

在另一个终端窗口里,可以登录 barney 然后连接到这个会话。连接时不必指定会话名,我们需要做的就是指定 socket 连接和 socket 文件的位置,就像这样:

barney@puzzles$ tmux -S /var/tmux/pairing attach

barney 用户现在已经连接到 tmux 会话而且他看到的就是 ted 用户所看到的内容。

需要注意的一点是,使用这种方法来使用 tmux 时,.tmux.conf 文件使用的配置是第一个启动这个会话的用户的配置。使用两个独立的账户并不意味着每个账户都可以在 tmux 会话里使用各自的配置文件,而是说他们可以根据其他的目的来定制他们的账户,然后在需要时都可以初始化他们所独有的 tmux 会话。

5.4 接下来做什么?

现在你已经学会了如何通过 tmux 与他人分享屏幕,你可以使用它来进行远程训练、在开源项目上进行即兴合作,或者是远程演示。

另外,还可以使用这个技术在你的生产服务器上开启 tmux 会话,加载监测工具或者控制台,然后从会话分离出来,让这些工具一直在后台运行。然后可以在你的机器上连接到这个会话,所有的一切都如你断开连接时那样。我曾经在我的开发环境上就做过类似的事情。我在一个 VPS 上配置了 tmux,然后在家里使用一台 iPad,一个 SSH 客户端以及一个蓝牙键盘就可以写代码了。即便是在 3G 网络下这样做依然很流畅。

结对编程和远程协作只是 tmux 应用在工作时提高工作效率的两个例子。在下一个章节,我们会学习在使用 tmux 窗口、面板和系统时其他更加高级的功能。

以备参考

命令 描述
tmux -S [socket] 使用 socket 创建一个新的会话
tmux -S [socket] attach 连接到一个已有的 socket 会话
tmux new-session -t [existing session] -s [new session] 创建一个到组会话的连接