Debian 12 混装跨版本包导致依赖崩盘:一次完整的抢救记录(从装不上 tmux 到 Python 全恢复)

这台 Debian 12 (bookworm) 上原本想装个 tmux,结果一路排下去发现系统被手动塞进了一批 testing/trixie 的新版本包(libtinfo6、ncurses、systemd、openssh…),跟 bookworm 的依赖矩阵彻底对不上,最后连 python3、openssh-server、cmake 都被拖下水卸掉了。

这篇记录完整的排查与修复过程:怎么把整批”跨版本包”一次性降回原生版本、再把被卸掉的关键包装回来,全程不留坑。

目录

一、起因:装 tmux 直接报”破坏依赖”

一开始只是想在 bookworm 上装个终端复用工具:

$ apt-get install tmux
...
下列软件包有未满足的依赖关系:
 libtinfo6 : 破坏: tmux (< 3.3a-4) 但是 3.3a-3 正要被安装
E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系。

这条报错看着像 Debian unstable 常见的”状态无法满足”,但 bookworm 是稳定版,不该出这种提示。往下查才发现不对劲。

二、定位:libtinfo6 是从”未来”装来的

先查 libtinfo6 当前装的是哪个版本:

$ dpkg -l libtinfo6 && apt-cache policy libtinfo6
ii  libtinfo6:amd64  6.6+20251231-1+b1  amd64  shared low-level terminfo library

libtinfo6:
  已安装:6.6+20251231-1+b1
  候选:  6.6+20251231-1+b1
  版本列表:
 *** 6.6+20251231-1+b1 100
        100 /var/lib/dpkg/status
     6.4-4 500
        500 http://deb.debian.org/debian bookworm/main amd64 Packages

两条关键信息:

  • 版本号 6.6+20251231-1+b1 里的日期戳是 2025-12-31,这显然是 testing/trixie 时代的构建,不属于 bookworm。
  • 它的优先级是 100 /var/lib/dpkg/status——也就是本地 dpkg 状态里登记的手动包,而不是从源候选进来的。说明之前有人(或某次操作)手动 dpkg -i 或从临时源把它拉了进来。

矛盾点:bookworm 自带的 tmux 3.3a-3 明确写了 Breaks: libtinfo6 (>= 新版),只能配旧版 6.4;系统里却被顶成了 6.6。两边对不上。

三、真凶:系统里混了一整批跨版本包

试着单独把 libtinfo6 降回 bookworm 的 6.4-4,又报 ncurses-bin 要求 libtinfo6 >= 6.6,形成循环依赖。再想降级,apt 提示要连带卸载 45 个包(含 python3、openssh-server、cmake、google-chrome、libncursesw6 等),根本不能这么干。

把”非 bookworm”的包全揪出来(dpkg -l 里带 bpo 或异常日期戳的):

$ dpkg -l | grep -Ei 'bpo|2025|2024|~rc'
ii  e2fsprogs             1.47.2-3~bpo12+1    amd64  ...
ii  iproute2              6.15.0-1~bpo12+1    amd64  ...
ii  libbpf1             1:1.4.6-1~bpo12+1   amd64  ...
ii  libelf1            0.192-4~bpo12+1      amd64  ...
ii  libsystemd-shared  254.26-1~bpo12+1    amd64  ...
ii  libsystemd0        254.26-1~bpo12+1    amd64  ...
ii  libudev1           254.26-1~bpo12+1    amd64  ...
ii  openssh-client     1:10.0p1-7~bpo12+1  amd64  ...
rc  openssh-server     1:10.0p1-7~bpo12+1  amd64  ...
ii  openssh-sftp-server 1:10.0p1-7~bpo12+1 amd64  ...
ii  systemd            254.26-1~bpo12+1    amd64  ...
ii  systemd-sysv       254.26-1~bpo12+1    amd64  ...
ii  udev               254.26-1~bpo12+1    amd64  ...
# 另外还有 coreutils 9.10-1、libncursesw6 6.6 等,比 bookworm 更新
注意 rc 状态:openssh-server 是 rc(已卸但配置文件保留),说明之前被删过一次又试图装回来——这也是依赖混乱的佐证。

结论:得把这整批包一次性降回 bookworm 原生版本,依赖链才能对齐。

四、抢救原则:成组降回 bookworm 原生版本

4.1 先查每个包在 bookworm 源里的精确版本号,别凭记忆

$ apt-cache policy coreutils e2fsprogs iproute2 libbpf1 libelf1 \
                  libext2fs2 openssh-client openssh-server systemd
# 每个包会列出「已安装 / 候选 / 版本列表」,抄 bookworm/main 源里
# 优先级 500 那一行的版本号(带 deb12 / 纯 bookworm 构建号)

4.2 一条命令成组降级(–allow-downgrades 必带)

$ apt-get install -y --allow-downgrades \
    coreutils=9.1-1 \
    e2fsprogs=1.47.0-2+b2 \
    libext2fs2=1.47.0-2+b2 \
    iproute2=6.1.0-3 \
    libbpf1=1:1.1.2-0+deb12u1 \
    libelf1=0.188-2.1 \
    openssh-client=1:9.2p1-2+deb12u10 \
    openssh-sftp-server=1:9.2p1-2+deb12u10 \
    openssh-server=1:9.2p1-2+deb12u10 \
    systemd=252.39-1~deb12u2 \
    systemd-sysv=252.39-1~deb12u2 \
    libsystemd-shared=252.39-1~deb12u2 \
    libsystemd0=252.39-1~deb12u2 \
    libudev1=252.39-1~deb12u2 \
    udev=252.39-1~deb12u2

几个要点:

  • --allow-downgrades 必须带,否则 apt 拒绝降级。
  • 配套包要一起写全:e2fsprogs 和 libext2fs2 是一对,只降一个会卡在「预依赖 libext2fs2 (= 1.47.0-2+b2) 但 1.47.2 正要被安装」。
  • openssh 的 client / server / sftp-server 三个要降到同一个 9.2p1-2+deb12u10,版本不一致又会咬上。
  • coreutils 这种核心工具降级前先确认有别的救援手段(云控制台 VNC / 其他环境),因为 ls/cp/mv/rm 会被替换。
降级前先模拟:apt-get -s install 看会不会连带卸载大量关键包,确认安全再真正执行。

五、收尾验证:SSH / tmux / Python 全恢复

降级完成后,被误卸的关键包要装回来。先看 Python 是不是也被卸了(当时那 45 个被卸载的包里就有 python3.11-venv):

$ dpkg -l | grep -E 'python3|venv'
ii  libpython3.11-minimal:amd64  3.11.2-6+deb12u9  amd64  ...
rc  python3                     3.11.2-1+b1        amd64  ...
ii  python3-minimal             3.11.2-1+b1        amd64  ...
rc  python3.11-venv             3.11.2-6+deb12u9   amd64  ...
# 注意:python3 和 python3.11-venv 都是 rc(已卸载),venv 模块因此缺失

这就是为什么后来 python3 -m venv 会报 No module named venv。装回来:

$ apt-get install -y python3 python3.11-venv
# 会新装 7 个包:python3 / python3.11 / python3.11-venv /
#   libpython3-stdlib / libpython3.11-stdlib / python3-distutils / python3-lib2to3

最终验证:

$ systemctl restart ssh && systemctl status ssh | head -3
● ssh.service - OpenBSD Secure Shell server
     Active: active (running) ...

$ tmux -V
tmux 3.3a

$ python3 --version
Python 3.11.2

$ python3 -m venv venv
# 成功,不再报 No module named venv
依赖体检:跑 apt-get check 确认没有未解决的依赖;再 systemctl --failed 看有没有挂掉的服务。

六、教训与铁律

这次崩盘的根本不是 tmux 或 python 本身,而是系统里被手动塞进了一批跨版本(testing/trixie 构建)的包,它们与 bookworm 的依赖矩阵对不上,连锁反应把一批基础包拖下水。

三条铁律:

  1. 别跨版本手动塞包:同一台机器上不要一会儿 bookworm、一会儿从 testing/trixie 拉包,混装必炸。临时需要新特性,用 docker / virtualenv / pyenv 隔离,别往系统里塞。
  2. 动手前先 apt-cache policy <pkg> 查可用版本,按源里真实存在的精确版本号写,别凭记忆。
  3. 降级要成组:把”被污染的整批包”列全(dpkg -l | grep -Ei 'bpo|20[0-9]{4}'),一条命令统一降回原生版本,配 --allow-downgrades,并保证配套包(server/client、e2fsprogs/libext2fs2)版本一致。

七、快速排查命令速查表

下次再遇到”装了个包却报破坏依赖 / 依赖对不上”,按这张表从上往下查,基本能定位是不是混版本包。

1. 先看依赖冲突卡在哪

# 模拟安装,不真装,看牵连哪些包 / 报什么冲突
apt-get -s install tmux

# 查某包的依赖关系(谁需要它、它需要什么、谁破坏它)
apt-cache depends tmux
apt-cache showpkg tmux

2. 揪出”非本版本”的包(关键)

# 列出所有带 bpo / 异常日期戳 / rc 的包
dpkg -l | grep -Ei 'bpo|2025|2024|~rc'

# 或找版本号里带「未来日期」或「rc」的
dpkg -l | awk '{print $1,$2,$3}' | grep -E '20[0-9]{4}|rc'

# 反查某包在源里到底有哪些版本(哪行是原生 500 优先级)
apt-cache policy libtinfo6

3. 确认某包”哪来的”

# 安装/移除历史(是不是手动 dpkg -i 或临时源拉的)
grep 'libtinfo6' /var/log/dpkg.log | tail -20

# 本地是否残留手动装的 deb
find /var/cache/apt/archives/ /tmp /root -name 'libtinfo*.deb' 2&gt;/dev/null

4. 成组降级前,把可用版本号抄齐

# 一次查全,抄「bookworm/main(优先级 500)」那行的版本号
apt-cache policy coreutils e2fsprogs iproute2 libbpf1 libelf1 \
                  libext2fs2 openssh-client openssh-server systemd

5. 一条命令成组降回原生版本

# 用第 4 步抄到的版本号拼成一条;--allow-downgrades 必带
apt-get install -y --allow-downgrades \
    coreutils=9.1-1 \
    e2fsprogs=1.47.0-2+b2 \
    libext2fs2=1.47.0-2+b2 \
    openssh-client=1:9.2p1-2+deb12u10 \
    openssh-server=1:9.2p1-2+deb12u10 \
    openssh-sftp-server=1:9.2p1-2+deb12u10 \
    systemd=252.39-1~deb12u2
# 配套包务必同一批、版本一致

6. 收尾验证

# 依赖是否还有未解决的
apt-get check

# 关键服务 / 工具能否正常跑
systemctl restart ssh &amp;&amp; systemctl status ssh | head -3
tmux -V
python3 --version &amp;&amp; python3 -m venv venv

排查口诀(六步法)

  1. apt-get -s install 模拟看冲突
  2. dpkg -l | grep -Ei 'bpo|20[0-9]{4}' 揪混版本包
  3. apt-cache policy 抄原生版本号
  4. apt-get install --allow-downgrades 成组降回
  5. 装回被误卸的关键包(python3 / openssh-server 等)
  6. apt-get check + 重启服务验证

全程别跨版本手动塞包,需要新特性就用 docker / virtualenv 隔离。

ChiuYut

2026年10月25日

发布者

ChiuYut

咦? 我是谁? 这是什么地方? Ya ha! 我是ChiuYut! 这里是我的小破站!