Skip to content

How to hold a package at its current version

Use this guide when an update to one package breaks something, or you need time to test a new version, and you want the rest of the system to keep receiving updates in the meantime. A hold stops the package manager upgrading the package until you release it.

A held package gets no security updates

While a package is held, fixes for it, including security fixes, aren't installed. Hold a package for as short a time as possible, record why and until when, and check the distribution's security advisories for it while the hold is in place. A hold can also block upgrades of other packages that need a newer version of the held one.

Before you begin

  • You need a shell with sudo on the machine.
  • The version of the package you want to keep is the one installed now. If it isn't, because the problem update has already been installed, first go back to the previous version as described in How to roll back a package update.
  • Replace <PACKAGE> with the name of the package, for example jq on Debian and Ubuntu, wget on the RHEL family, tree on Arch and app-text/tree (category and name) on Gentoo.

Steps

  1. Mark the package as held:

    $ sudo apt-mark hold <PACKAGE>
    jq set on hold.
    

    The hold is a dpkg selection state, so apt, apt-get, unattended-upgrades and other front ends all respect it.

  2. Check which packages are held:

    $ apt-mark showhold
    jq
    
  1. Install the version lock plugin for dnf, if it isn't installed:

    sudo dnf install -y python3-dnf-plugin-versionlock
    
  2. Lock the package at the installed version:

    $ sudo dnf versionlock add <PACKAGE>
    Adding versionlock on: wget-0:1.24.5-5.el10.*
    

    The plugin records the lock in /etc/dnf/plugins/versionlock.list, and from then on dnf ignores every other version of the package.

  3. Check which packages are locked:

    $ dnf versionlock list
    wget-0:1.24.5-5.el10.*
    

The exclude= option in /etc/dnf/dnf.conf is a blunter alternative: it hides the package from dnf completely, so it can't be installed or reinstalled either.

Partial upgrades aren't supported

Arch packages are built against the current versions of each other. A held package keeps using the libraries it was built against, and can stop working when one of them is upgraded without it; pacman doesn't check for this. Release the hold as soon as you can.

  1. List the package in the IgnorePkg option in the [options] section of /etc/pacman.conf. The default file contains a commented-out #IgnorePkg = line; this command replaces it:

    sudo sed -i 's/^#IgnorePkg *=.*/IgnorePkg   = <PACKAGE>/' /etc/pacman.conf
    

    If the file already has an uncommented IgnorePkg line, add the package to that line instead, separated from the others by a space.

  2. Check the setting as pacman reads it:

    $ pacman-conf IgnorePkg
    tree
    

Portage has no hold command: you mask every version newer than the installed one.

  1. Find the installed version:

    $ qlist -Iv <PACKAGE>
    app-text/tree-2.1.1-r1
    

    Replace <VERSION> in the next step with the version after the package name, here 2.1.1-r1.

  2. Mask the newer versions, in a file named after the package and the reason, so that it's easy to find and remove later. <NAME> is the package name without its category, here tree:

    sudo install -d /etc/portage/package.mask
    echo '><PACKAGE>-<VERSION>' | sudo tee /etc/portage/package.mask/hold-<NAME>
    

    The > operator matches every version greater than the one given. If /etc/portage/package.mask already exists as a file rather than a directory, add the line to that file instead.

If you accepted testing versions of the package (~amd64) in /etc/portage/package.accept_keywords, the mask still holds it at the installed version. Removing the package.accept_keywords entry instead would only stop it moving to newer testing versions; the next stable version would still be installed.

Verify

Run a full upgrade, or simulate one, and check that the package is left at its version:

$ sudo apt-get update
$ apt-get upgrade --simulate
Reading package lists...
Building dependency tree...
Reading state information...
Calculating upgrade...
The following packages have been kept back:
  jq libjq1
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.

Here libjq1 is kept back too, because jq requires exactly its own version of the library. Requesting the package explicitly with -y fails instead of upgrading it; without -y, apt-get lists it under The following held packages will be changed and asks for confirmation:

$ sudo apt-get install -y <PACKAGE>
The following held packages will be changed:
  jq
The following packages will be upgraded:
  jq libjq1
2 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
E: Held packages were changed and -y was used without --allow-change-held-packages.

$ sudo dnf upgrade -y <PACKAGE>
Dependencies resolved.
Nothing to do.
Complete!
$ rpm -q <PACKAGE>
wget-1.24.5-5.el10.x86_64
$ sudo pacman -Syu --noconfirm
:: Synchronizing package databases...
:: Starting full system upgrade...
warning: tree: ignoring package upgrade (2.3.1-1 => 2.3.2-1)
 there is nothing to do

pacman -Qu lists the held package with [ignored] after the version it would upgrade to. sudo pacman -S <PACKAGE> still upgrades the package, after asking whether to install it anyway.

Plan a full update; the held package isn't in it:

emerge --pretend --update --deep --newuse --getbinpkg @world

Asking for a newer version explicitly fails, because every newer version is masked:

$ emerge --pretend '><PACKAGE>-<VERSION>'
!!! All ebuilds that could satisfy ">app-text/tree-2.1.1-r1" have been masked.
!!! One of the following masked packages is required to complete your request:
- app-text/tree-2.3.2::gentoo (masked by: package.mask, ~amd64 keyword)
- app-text/tree-2.2.1::gentoo (masked by: package.mask)

Release the hold

When you're ready to take the new version, release the hold and upgrade:

sudo apt-mark unhold <PACKAGE>
sudo apt-get install -y --only-upgrade <PACKAGE>

--only-upgrade upgrades the package, and the packages that need to be upgraded with it such as libjq1 here, without upgrading anything else; sudo apt-get upgrade upgrades the whole system instead.

sudo dnf versionlock delete <PACKAGE>
sudo dnf upgrade -y <PACKAGE>

Remove the package from the IgnorePkg line (this command restores the commented-out default line), then upgrade:

sudo sed -i 's/^IgnorePkg *= *<PACKAGE>$/#IgnorePkg   =/' /etc/pacman.conf
sudo pacman -Syu --noconfirm
sudo rm /etc/portage/package.mask/hold-<NAME>
sudo emerge --update --getbinpkg <PACKAGE>

This upgrades only the held package, and any dependencies it needs newer versions of; it stays in your @world set if it was there. Your next @world update would also have upgraded it.

Troubleshooting

apt reports The following packages have been kept back for packages you didn't hold
Other packages depend on an exact version of the held one, as libjq1 does here, or a newer version of them needs a newer version of it. They upgrade once you release the hold.
dnf versionlock reports No such command
The plugin isn't installed. Install python3-dnf-plugin-versionlock.
dnf reports a dependency problem involving a locked package
Another update needs a newer version of the locked package. Either release the lock, or exclude that update for now with sudo dnf upgrade --exclude=<OTHER_PACKAGE>, where <OTHER_PACKAGE> is the package dnf names.
emerge reports a conflict or masked by: package.mask for a dependency on Gentoo
A package you're upgrading needs a version of the held package that your mask hides. Release the hold, or keep the dependent package at its version too, until you can take both.