How to easily exclude packages from apt-get upgrades

Once you’ve got the hang of Debian/Ubuntu’s package management system and have had a fine time smoothly upgrading your system periodically, at some point the inevitable will happen: while upgrading a package something will get installed that will break something else.

It could be, as happened to me recently, a version of Google Chrome that won’t play nice with some element of Gnome or the GTK toolkit – any button on a webpage that should launch a dialogue box took minutes to do so. Several minutes. So we need to reverse this, by downgrading the package to the previous version, and then prevent it from being reinstalled automatically. How?

The most common Debian package manager frontend is apt-get. There are a number of different options, from powerful but complex dpkg, it’s more user-friendly brother aptitude, to the full blown X-windows GUI of synaptic. But apt-get is most people’s first choice, the most straightforward, and the one which comes with no obvious switch or option included – the following demonstrates how.


1) Remove and downgrade the problem package

This is straightforward. First find the problematic package version:

$ sudo cat /var/log/apt/term.log | grep google-chrome-stable
Setting up google-chrome-stable (32.0.1700.77-1) ...
Preparing to replace google-chrome-stable 32.0.1700.77-1 (using .../google-chrome-stable_32.0.1700.102-1_amd64.deb) ...
Unpacking replacement google-chrome-stable ...
Setting up google-chrome-stable (32.0.1700.102-1) ...

There in the apt logfile is the output of the apt-get command that installed the package we want to replace, version 32.0.1700.102-1. Now we find the packages in the apt package cache:

$ ls -l /var/cache/apt/archives/google-chrome-stable*

There’s the last few versions. It’s simple enough to replace the most recent with the previous version using dpkg.

$ dpkg -i /var/cache/apt/archives/google-chrome-stable_32.0.1700.77-1_amd64.deb


2) Prevent the next apt-get update or dist-update from upgrading the package

The package manager records packages as flagged in one or more of various states, such as installed (or set to be installed), not installed (or set to be removed) or held. For this purpose we need to hold the package. There are two ways of doing this.

One is to use dpkg again, using –set-selections to set the package flags.

$ echo "google-chrome-stable hold" | sudo dpkg --set-selections

(note it’s dpkg that requires root privileges, not echo)

We can check this has worked:

$ dpkg --list | grep google-chrome-stable
hi google-chrome-stable 32.0.1700.77-1 amd64 The web browser from Google

Where the “hi” at the beginning of the line stands for “hold” and “installed”. You can read up more about the different package statuses, how to check them and what they mean in the dpkg-query manpage.

Now when we run an upgrade using apt-get, the held package will be ignored:

$ sudo apt-get upgrade
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages have been kept back:
The following packages will be upgraded:
curl libcurl3 libcurl3-gnutls
3 upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
Need to get 1,258 kB of archives.
After this operation, 39.9 kB of additional disk space will be used.
Do you want to continue [Y/n]?

You can easily check which version of the held package installed and the package offered from the repo by running apt-get install on the package with the -s (“simulate”) switch, which reports the package versions:

$ sudo apt-get install google-chrome-stable -s
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following held packages will be changed:
The following packages will be upgraded:
1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Inst google-chrome-stable [32.0.1700.77-1] (32.0.1700.107-1 Google:1.0/stable [amd64])
Conf google-chrome-stable (32.0.1700.107-1 Google:1.0/stable [amd64])

At some point we’ll want to reverse this decision, as bugs will have been fixed and versions incremented. So we can unhold the package by setting it to install, where the “ii” refers to “set for installation” and “installed”:

$ echo "google-chrome-stable install" | sudo dpkg --set-selections
$ dpkg --list | grep google-chrome-stable
ii google-chrome-stable 32.0.1700.77-1 amd64 The web browser from Google


The alternative is to use apt-mark. This is chiefly for marking packages as either automatically or manually installed, which affects how they respond to being installed, upgraded or removed as dependencies to other packages. For example, a package set to auto will be automatically installed as a dependency to another package if required, and automatically removed if not required; those set to manual will not.

But it also can be used to hold packages – in fact, it is a wrapper around dpkg --set-selections, and works in exactly the same way albeit in a slightly simpler fashion.

$ apt-mark hold google-chrome-stable
$ apt-mark showhold
$ sudo apt-mark unhold google-chrome-stable
$ apt-mark showhold

And there you are. More straightforward than pinning using apt’s preferences file (with less margin for disaster), and easily reversible.

Using Ubuntu PPA packages with Debian or Crunchbang

Ah, the joys of package management. Every linux distribution flavour has a package management tool – even the venerable Slackware – to ensure the otherwise near-impossible task of installing programs and their dependencies and updating them to the latest versions is made possible for mere mortals.

Ubuntu, based on Debian, uses the same apt-get and dpkg tools. But as the pace of development at Ubuntu is much quicker and has a broader reach of users and developers than vanilla Debian, Canonical introduced PPA – personal package archives – on its Launchpad service to allow developers to create and maintain their own packages that can be accessed by Ubuntu users through apt-get, without having to bring them into the Ubuntu official release package tree itself.

While built for Ubuntu releases specifically, these packages can be used with Debian – and therefore Crunchbang – without much hassle. Two things are needed: firstly the location of the archive, usually an http:// or https:// web address; secondly the GPG encryption key that is used to sign the .deb packages, ensuring that the software you are installing on your computer with root permissions is, at least to a point, trusted.

In Ubuntu this is taken care of either using the add-apt-repository command, or by adding the package source using the Synaptic package manager GUI app. Neither comes with the stripped down and Gnome/KDE-free Crunchbang.

Instead we go old school again and edit the text file that the graphical app would be doing for us anyway, /etc/apt/sources.list. In this case, I’m installing the Darktable photo management and editing package, a sort of open source Adobe Lightroom. The PPA address can be found from the Ubuntu PPA achive on Launchpad. A search reveals the individual page(s) for Darktable.

In this example, there are three pages for Darktable, darktable-release, -release-plus, and -unstable. I’m using the cutting edge -unstable release in this case. Debian Squeeze (6.0.1) came out in February 2011, but I’ve used packages from the Ubuntu 10.04 “Lucid Lynx” release from April 2010 as it is a Long Term Support version and will continue to be updated long after Ubuntu 10.10 “Maverick Meercat” has been archived. Click the green link marked Technical Details about this PPA to reveal the source lines we need, beginning with deb:

We need to add the following text to /etc/apt/sources.list:

deb lucid main
deb-src lucid main

Darktable-unstable is the cutting-edge version in this case. The same deb line but substituting the words “darktable-release” would install from the more stable branch.

Running sudo apt-get update will force apt to add the new PPA repository to its list, but it will complain that it doesn’t have the GPG encryption keys we need to install packages:

Hit lucid/main Sources
Hit lucid/main amd64 Packages
Fetched 634 B in 0s (1,172 B/s)
Reading package lists... Done
W: GPG error: lucid Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 40C18E9EC07EE05F

To add the key we use the apt-key tool. Under the PPA source lines on the Darktable page, under the title Signing Key is an eight-character key, prefixed with 1024R/ (= 1024-bit RSA encryption). The key is per-user, so will be the same for each of the Darktable releases created by Pascal de Bruijn. To add it to our GPG keychain, the command we need is:

$ sudo apt-key adv --keyserver --recv-keys C07EE05F

Executing: gpg --ignore-time-conflict --no-options --no-default-keyring --secret-keyring /etc/apt/secring.gpg --trustdb-name /etc/apt/trustdb.gpg --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --keyserver --recv-keys C07EE05F
gpg: requesting key C07EE05F from hkp server
gpg: key C07EE05F: public key "Launchpad PPA for Pascal de Bruijn" imported
gpg: Total number processed: 1
gpg: imported: 1 (RSA: 1)

Follow this with another sudo apt-get update, and we’re done. You can install away using the usual method, for example: sudo apt-get install darktable.

It’s a little less polished than Ubuntu’s tools, but what you lose in convenience you gain in speed and responsiveness, and a better understanding of how the system works underneath – a price worth paying, imho.

UPDATE: It’s worth noting that up-to-date versions of Darktable packages now appear in Debian Wheezy (1.0.4-1) and Debian Sid (1.0.5-1).