Home / Alt manpages / dpkg-divert(1)

  • dpkg-divert(1)
  • User command
  • linux

Safely divert a Debian package file with dpkg-divert

You will move a package-owned file to a second path, leave the package manager's diversion record in place, and install or keep your own replacement at the original path. You will also verify the result and remove the diversion without guessing what dpkg will do next. Allow about fifteen minutes. You need a Debian-family system with the dpkg package database and a clear reason to override a file.

The examples use dpkg-divert 1.22.6, from dpkg package version 1.22.6ubuntu6.6 on this machine. Run the state-changing commands as root, normally through sudo. The inspection commands can usually be run without elevation.

1. Choose the original and diverted paths

Pick the exact file that a package installs and a separate path where future package copies should go. This guide uses a fictional executable so that the names are obvious:

ORIGINAL=/usr/bin/example
DIVERTED=/usr/bin/example.distrib

Do not use a directory. dpkg-divert cannot divert directories. Also avoid shared libraries unless you have checked the dynamic-linker consequences: the manual warns that ldconfig does not honour diversions when creating SONAME links.

Inspect the current paths before changing anything:

$ command -v dpkg-divert
/usr/bin/dpkg-divert
$ dpkg-divert --listpackage "$ORIGINAL"
$ dpkg-divert --truename "$ORIGINAL"
/usr/bin/example

An empty result from --listpackage means that no diversion is currently recorded for this file. The --truename output is the path where the real package file is currently expected. If another diversion already exists, stop and understand it before adding or removing anything.

2. Preview the diversion

Use --test before the real operation. It demonstrates the action without updating the database or renaming the file:

$ sudo dpkg-divert --divert "$DIVERTED" --rename --test "$ORIGINAL"
Adding 'local diversion of /usr/bin/example to /usr/bin/example.distrib'

The default when adding a diversion is local, with the diverted name set to ORIGINAL.distrib. Supplying --divert makes the destination explicit. --rename is also explicit here because it actually moves the existing file. Without it, the diversion record changes but the file is not moved. On this installed version, --no-rename is the default and the manual says that this default is expected to change in the dpkg 1.20.x cycle; do not rely on an unstated default in a script.

Checkpoint: the preview should say Adding, and it should name the paths you intended. If it proposes a different file, do not continue.

3. Add the local diversion and move the package copy

After checking the preview, perform the operation:

$ sudo dpkg-divert --divert "$DIVERTED" --rename "$ORIGINAL"
Adding 'local diversion of /usr/bin/example to /usr/bin/example.distrib'

This records a diversion for all packages and moves an existing /usr/bin/example to /usr/bin/example.distrib. Put your replacement at the original path only after the command succeeds. For example, install a reviewed local file with its normal deployment method, then check both paths:

$ ls -l "$ORIGINAL" "$DIVERTED"
$ dpkg-divert --list "$ORIGINAL"
local diversion of /usr/bin/example to /usr/bin/example.distrib
$ dpkg-divert --listpackage "$ORIGINAL"
LOCAL

If the destination already exists, --rename aborts rather than overwriting it. Treat that as a safety stop. Compare the two files and choose a non-conflicting destination rather than deleting a file blindly.

4. Handle package-specific exceptions deliberately

A local diversion applies to every package. If one named package should still install the original path, specify that package instead of using the local default:

$ sudo dpkg-divert --package wibble \
    --divert /usr/bin/example.wibble \
    --rename /usr/bin/example

This means that /usr/bin/example is diverted for packages other than wibble. Use the package name exactly as recorded by dpkg. If a maintainer script invokes dpkg-divert, it may use DPKG_MAINTSCRIPT_PACKAGE as the package name when neither --local nor --package was supplied. For an administrator's override, being explicit with --local or --package is easier to review.

5. Remove the diversion with a matching definition

Removing a diversion is a state change and may move the diverted file back. First preview it with the same destination and package scope used when adding it:

$ sudo dpkg-divert --divert "$DIVERTED" --rename --remove --test "$ORIGINAL"
Removing 'local diversion of /usr/bin/example to /usr/bin/example.distrib'

For the local example, complete the removal only after checking that the original path is free or that you have a deliberate recovery plan:

$ sudo dpkg-divert --divert "$DIVERTED" --rename --remove "$ORIGINAL"
Removing 'local diversion of /usr/bin/example to /usr/bin/example.distrib'
$ dpkg-divert --listpackage "$ORIGINAL"
$ dpkg-divert --truename "$ORIGINAL"
/usr/bin/example

After removal, the diverted file is moved back to the original name. If you placed a local replacement there, move it somewhere safe first. Never assume that --remove will merge two files. With --rename, an existing destination can cause the operation to abort rather than overwrite it.

6. Check common failure modes

If a command reports that the file is not diverted, inspect the exact spelling, the administrative directory and any root setting. By default, the database is under /var/lib/dpkg. DPKG_ADMINDIR or --admindir can select another database, while DPKG_ROOT, --root and --instdir affect the installation tree. Use these options together when working on an offline root, and do not accidentally update the host's live database.

The diversion database is /var/lib/dpkg/diversions, or the equivalent path under the selected administrative directory. Before replacing it, dpkg-divert keeps an old copy in diversions-old. Do not edit either file by hand while a package operation is running.

A successful exit status is zero. Fatal usage or system errors return status 2. Capture that status immediately in scripts and stop on failure. The command changes package-manager state, so keep the original file and your replacement under version control or another recoverable backup until an upgrade has completed successfully.

Done means

  • The original file and diverted destination were chosen as separate, exact paths.
  • --test showed the intended add and remove operations before either state change.
  • --rename moved the package copy and no existing destination was overwritten.
  • --list, --listpackage and --truename confirm the recorded state.
  • The removal command matches the original diversion and the replacement is backed up before files move.