Debian, also known as “the universal operating system”, is one of the oldest Linux distributions. At any point in time there are always three main Debian releases: stable, testing and unstable. The “stable” release represents the official Debian release: it is rock solid, ready for production, and contains packages which doesn’t change much. The “testing” release contains packages which are on their road to be accepted into stable, and finally, the “unstable” release is the one with the most updated versions of software, used for the distribution development.
In this tutorial we see how to install packages from testing and unstable on the stable version of Debian, using the “pinning” technique.
In this tutorial you will learn:
- How to add testing and unstable repositories to Debian “stable” software sources
- How packages priorities are assigned by default
- How to configure pinning
- How to explicitly install a package from “testing” or “unstable”
|Category||Requirements, Conventions or Software Version Used|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux-commands to be executed as a regular non-privileged user
Adding Debian testing and unstable repositories to the stable release
Mixing packages from different Debian releases must be avoided unless there are no alternatives available. That said, to install packages from testing or unstable into the stable release of Debian, the first thing we need to do is to add the respective repositories to the distribution software sources. The most straightforward way to accomplish this task is to add the following entries into the
deb http://deb.debian.org/debian testing main contrib deb http://deb.debian.org/debian unstable main contrib
Debian releases are named after Toy Story characters. At the moment of writing, for instance, the stable version of is named “bullseye”, while testing is named “bookworm” (the unstable release is always named “sid”). In the
/etc/apt/sources.listfile, releases can either be referenced by their names, or by the release class itself (stable/testing/unstable). In the example below we adopted the latter strategy.
Each Debian release repository has basically three “components”: main, contrib and non-free. The “main” component contains only free and open source software; the “contrib” component contains free and open source software which has some non-free dependencies. Finally, the “non-free” component contains software which don’t comply with the Debian Free Software Guidelines. A “backports” component (bullseye-backports in the case of the current Debian “stable” release), is also available as a safe way to provide more up-to-date software recompiled from
“testing” against libraries already available on “stable”. In the example above, as you can see, we used only the first two components.
Once the testing and/or unstable repositories have been added as software sources, we must change package priorities depending on how we want the system to behave. Let’s see how to do that.
How priorities are assigned by default
When multiple versions of the same package are available, to choose which one should be installed, APT uses a priority system. Before learning how package priorities can be explicitly set in the /etc/apt/preferences file (or in dedicated files under the /etc/apt/preferences.d directory), we must get a grasp on how priorities are assigned. This depends on whether or not a target release is defined. The Debian target release is undefined by default, but can be set into the
/etc/apt/apt.conf file. For instance, to set “stable” as the target release, we would write:
If the target release is defined, packages from it get the highest priority:
- Priority 100 is assigned to packages already installed.
- Priority 900 is assigned to packages from the target release
- Priority 500 is assigned to other packages
If the target release is not defined, instead, priority 100 is assigned to installed packages, while all available packages get a priority of 500. The highest available version of a package is selected as a candidate for installation, and packages are never allowed to be downgraded, unless their priority is explicitly set to be > 1000. More specifically priority values (integers) are interpreted by APT in the following way:
- Priority < 0: prevents the installation of a package version
- Priority value between 1 and 99: causes a version to be installed only if there is no installed version of the package.
- Priority between 100 and 499: causes a version to be installed unless there is a version available belonging to some other distribution or the installed version is more recent
- Priority between 500 and 989: causes a version to be installed unless there is a version available belonging to the target release or the installed version is more recent
- Priority between 990 and 999: causes a version to be installed even if it does not come from the target release, unless the installed version is more recent
- Priority > 1000: causes a version to be installed even if this constitutes a downgrade of the package
Priorities can be overwritten by defining rules into the
/etc/apt/preferences file. Let’s see how.
The /etc/apt/preferences file
To define a rule in the
/etc/apt/preferences file, we must provide three information:
- Tha patterns which should match for the rule to be applied (this can be a package name, a POSIX extended regex, or “*” to match all available packages)
- The package version, origin, or release
- The package priority
Let’s see some examples. As we specified above, when the target release is not defined, the most updated version of a package is selected as installation candidate. We added the testing and unstable releases as software sources, therefore, since the latter contains the most updated packages, software we attempt to install should be pulled from it (if available). Suppose we want to install ansible; to verify what we just said is true, we can use the
apt-cache policy command, which displays the priority of each software source and the package version which would be selected as installation candidate, if a package name is passed as argument. We run:
$ apt-cache policy ansible
The command returns the following output:
ansible: Installed: (none) Candidate: 7.3.0+dfsg-1 Version table: 7.3.0+dfsg-1 500 500 http://deb.debian.org/debian testing/main amd64 Packages 500 http://deb.debian.org/debian unstable/main amd64 Packages 2.10.7+merged+base+2.10.8+dfsg-1 500 500 http://deb.debian.org/debian bullseye/main amd64 Packages
As you can see the
7.3.0+dfsg-1version of the package is available in both the “testing” and “unstable” repositories, while the “stable” repository contains the
2.10.7+merged+base+2.10.8+dfsg-1version, which is older. All versions have the same priority (500), however, the newest one is chosen.
Now, suppose we want to add the testing and unstable repositories to our Debian “stable” system, but we want to install packages from them only on explicit request. Without setting a target release, we could define the following rules and assign a lower priority to packages from testing and unstable:
Package: * Pin: release a=stable Pin-Priority: 900 Package: * Pin: release a=testing Pin-Priority: 600 Package: * Pin: release a=unstable Pin-Priority: 500
The rules above match all packages, since we used a “*” (a glob expression). POSIX extended regular expressions can also be used. To match a specific package we would have just entered its name, instead. We pinned packages by release archive (that’s what the “a” in “a=stable” stands for), and we assigned decreasing priorities starting from “stable” (priority 900), than “testing” (priority 600) and finally “unstable” (priority 500). Releases can be selected also by their “name”, for instance, we could write:
Package: * Pin: release n=bullseye Pin-Priority: 900
We save the rules and re-check the output of the apt-cache command. As you can see, this time the package selected as installation candidate is the one coming from the stable repository, which has an higher priority:
ansible: Installed: (none) Candidate: 2.10.7+merged+base+2.10.8+dfsg-1 Version table: 7.3.0+dfsg-1 600 600 http://deb.debian.org/debian testing/main amd64 Packages 500 http://deb.debian.org/debian unstable/main amd64 Packages 2.10.7+merged+base+2.10.8+dfsg-1 900 900 http://deb.debian.org/debian bullseye/main amd64 Packages
In such situation, how to install a package from testing or unstable explicitly? We can temporarily define the “target release” from the command line, using the
--target-release) at runtime, for a single command. This will make so that the package and its dependencies are installed from the specified release, or, if already installed, updated to the version in the target release if the package requires it. For instance, to install the “ansible” package using “testing” as the target release, we would run:
$ sudo apt-get install -t testing ansible
To install only the package from a specific release, but try to satisfy its dependencies according to the established priorities, instead, we would run:
$ sudo apt-get install ansible/testing
This, however, most of the time could lead to errors like the following:
The following packages have unmet dependencies: ansible-core : Depends: python3-jinja2 (>= 3.0.0~) but 2.11.3-1 is to be installed
It goes by itself that one should be extremely careful and inspect pre-installation reports with extreme attention when mixing packages from different Debian releases. You should always check if an updated version of a package is available in the “backports” repository before mixing software from different Debian releases.
In this tutorial we saw how it’s possible to include software repositories from Debian testing and unstable into the stable release, and define package priorities using the “pinning” technique. We learned how priorities are assigned depending on whether a target/default Debian release is defined, and we saw how to override the default behavior by specifying priority rules. For more examples, please take a look at the