I switched from Ubuntu to Debian so that I don’t need to update the code name in /etc/apt/sources.list every time a new release comes out. The following is some configs and commands I find useful.

1
2
3
4
5
6
7
8
9
10
$ cat /etc/apt/sources.list
deb http://deb.debian.org/debian stable main contrib non-free non-free-firmware
deb http://deb.debian.org/debian testing main contrib non-free
deb http://deb.debian.org/debian unstable main contrib non-free

deb http://security.debian.org/debian-security stable-security main
deb http://security.debian.org/debian-security testing-security main

deb http://deb.debian.org/debian stable-updates main contrib non-free non-free-firmware
deb http://deb.debian.org/debian testing-updates main contrib non-free

Here I am mixing packages from multiple releases, which basically throws stability out of the window. However, by mostly sticking to packages in stable, one can get a system that’s stable enough but still access the latest release of certain packages, e.g. clang.

We need to tell APT to prefer packages from stable over ones from testing/unstable in order to maximize the set of stable packages. (There is a high confidence that packages in stable play well with each other, but the same can’t be said for other releases.) Such bias can be achieved easily with a larger priority score for stable releases.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat /etc/apt/preferences
# The default value is 500, which means packages from stable-security will be upgraded automatically.
# To prevent that, one can use:
# Package: *
# Pin: release a=stable
# Pin-Priority: 600

Package: *
Pin: release a=testing
Pin-Priority: 60

Package: *
Pin: release a=unstable
Pin-Priority: 50

Note that we are using priority <100 for packages from non-stable releases, which ensures that only packages from stable release will be upgraded via apt upgrade or commands alike, because already installed packages have priority 100.

For installing and upgrading specific packages in non-stable releases, one can use apt install -t testing <package_name> or apt install -t unstable <package_name>. For example:

1
$ apt install --dry-run -t testing neovim # using --dry-run to first see what will happen

Occasionally, we might want to know what packages are installed from one specific release, e.g. unstable:

1
2
$ apt-show-versions | grep unstable
conky:all/unstable 1.10.8-1 uptodate

or, what versions exit in different releases:

1
2
3
4
5
6
7
8
9
10
11
$ apt policy clang
clang:
Installed: 1:13.0-53
Candidate: 1:13.0-53
Version table:
*** 1:13.0-53 100
50 http://deb.debian.org/debian unstable/main amd64 Packages
100 /var/lib/dpkg/status
1:11.0-51+nmu5 600
600 http://deb.debian.org/debian stable/main amd64 Packages
60 http://deb.debian.org/debian testing/main amd64 Packages

§Deprecated

I was using the testing release + Unattended-upgrade (u-u) with the hope of achieving a balance between stability and an up-to-date system, but I encountered two problems serious enough to block my normal work (the first being some packages are pulled into testing, but its dependencies are still left in unstable, and the second broke my apt/dpkg for unknown reasons). Therefore, I reinstalled my system and switched back to stable release. Packages in stable don’t see many frequent updates, so I don’t have a use case for u-u anymore; the following u-u configs are just for archiving purposes.

§u-u configs

As for staying updated, u-u has been working quite alright mostly with the following configs. However, when it does not, I run sudo apt dist-upgrade and it gets me out of trouble.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ cat /etc/apt/apt.conf.d/20auto-upgrades
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::CleanInterval "7";
# silently update as "stable/testing" advances, if needed
# Acquire::AllowReleaseInfoChange::Codename "true";


$ cat /etc/apt/apt.conf.d/50unattended-upgrades
Unattended-Upgrade::Origins-Pattern {
"o=Debian,a=testing";
"o=Debian,a=testing-updates";
"o=Heroku,a=stable";
"site=dl.bintray.com";
};

Unattended-Upgrade::Package-Blacklist {
// auto upgrading the kernel seems a bit too adventurous
"linux-";
};

Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";

§APT timers

List apt-related timers:

1
2
3
$ systemctl list-timers | grep apt
Mon 2020-12-21 03:03:49 CET 12h left Sun 2020-12-20 06:00:34 CET 8h ago apt-daily.timer apt-daily.service
Mon 2020-12-21 06:56:10 CET 16h left Sun 2020-12-20 06:23:34 CET 7h ago apt-daily-upgrade.timer apt-daily-upgrade.service

apt-daily.timer decides when to download upgradable packages, and apt-daily-upgrade.timer decides when to perform upgrade/cleanup. Since my network connection is rather slow, I prefer downloading happens during night, so I override the default apt-daily.timer with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ sudo systemctl edit apt-daily.timer

# use the following content in the editor
[Unit]
Description=Daily apt download activities

[Timer]
OnCalendar=
OnCalendar=*-*-* 3:00
RandomizedDelaySec=10m
Persistent=true

[Install]
WantedBy=timers.target

Then, we can confirm that our new config works fine with systemctl status apt-daily.timer, the next trigger is around 3:00` next day.