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*
/var/cache/apt/archives/google-chrome-stable_32.0.1700.77-1_amd64.deb
/var/cache/apt/archives/google-chrome-stable_32.0.1700.102-1_amd64.deb

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:
google-chrome-stable
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:
google-chrome-stable
The following packages will be upgraded:
google-chrome-stable
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
google-chrome-stable
$ 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.



One Comment

  1. Hajo Baess wrote:

    Thank you for this great tutorial! I needed to prevent a Firefox upgrade for similar reasons as you described above with Chrome. And it works perfectly. I gladly bookmarked it for later use. You never know…

    All best
    Hajo

Leave a Reply