80

Is there a way, before starting an aptitude upgrade or apt-get upgrade, to set up something so that you can "easily" rollback your system to the "apt" state it was before the actual upgrade, if something goes wrong?

That is, for example, reinstall the old version of the packages that were upgraded during the process.

(EDIT) A few hints: I know that etckeeper for example uses some hook on apt so that it is notified whenever apt installs or uninstalls a package. I suppose there could be some kind of script that could save the list of newly installed package and their previous version number to be able to reinstall them from the apt cache (/var/cache/apt/archives). There is also checkinstall which can keep track of file modifications...

Any details on how to achieve that properly?

Totor
  • 20,040
  • I am not aware that apt has something like that build in, you would have to keep track of the currently installed package numbers etc. Easier IMHO just to restore yesterdays backup if necessary. – Anthon Jun 11 '13 at 19:00

3 Answers3

67

I just now had to figure out an answer to this, because the last apt-get upgrade on a Debian server made it impossible to boot the most recent kernel beyond a busybox, failing to mount the zfs root partition. At least an older kernel could still boot, but was incompatible with other software. Thus the need for a rollback.

The short answer - you could use the following command:

$ apt-get -s install $(apt-history rollback | tr '\n' ' ')

if it does what you want remove the -s and run it again. Here are the steps I took to get this working properly:

  1. I temporarily trimmed my /var/log/dpkg.log to leave just today's upgrade

  2. I installed the tiny script apt-history from here into ~/.bashrc and ran

    $ apt-history rollback > rollback.txt
    ...
    libzfs2:amd64=0.6.4-4~wheezy 
    zfsutils:amd64=0.6.4-4~wheezy 
    zfs-initramfs:amd64=0.6.4-4~wheezy
    ...
    
  3. This provides a nicely formatted list of versioned packages to roll-back to by feeding it into apt-get install. Trim this list as needed in a text editor and then run (with -s for dry-run first):

    $ apt-get -s install $(cat rollback.txt | tr '\n' ' ')
    $ apt-get install $(cat rollback.txt | tr '\n' ' ')
    

Apt will warn about the downgrades which is expected. To prevent this rollback to be overwritten by the next upgrade, the packages will need to be pinned, until the original issue is resolved. For example with: apt-mark hold zfsutils libzfs2 ...


function apt-history(){
    case "$1" in
      install)
            cat /var/log/dpkg.log | grep 'install '
            ;;
      upgrade|remove)
            cat /var/log/dpkg.log | grep $1
            ;;
      rollback)
            cat /var/log/dpkg.log | grep upgrade | \
                grep "$2" -A10000000 | \
                grep "$3" -B10000000 | \
                awk '{print $4"="$5}'
            ;;
      *)
            cat /var/log/dpkg.log
            ;;
    esac
}
fra-san
  • 10,205
  • 2
  • 22
  • 43
ChrisW
  • 815
  • 4
    The apt-history rollback command can be replaced with something like awk '$3 ~ /upgrade/ {print $4"="$5}' dpkg.log. – Totor Jul 17 '17 at 12:18
  • 5
    With following extension, it only matches upgrades of the given date (so no need to modify the log before): awk '$1 == "2018-09-07" && $3 == "upgrade" {print $4"="$5}' /var/log/dpkg.log – luator Sep 07 '18 at 09:15
  • 3
    After trimming dpkg.log I get a bunch of version not found messages, i.e. E: Version '5.24.1-3+deb9u3' for 'libperl5.24' was not found. I'm using Debian Stretch for Raspian. – a2f0 Sep 21 '18 at 04:33
  • 2
    Nice solution but somehow I get for all the packages that this specific version was not found... – phrogg Feb 05 '20 at 10:40
  • What exactly did you do in step 1? Did you remove all lines except those that were written during the apt-get upgrade you want to revert? – Osvald Laurits May 08 '20 at 09:51
  • Will this rollback operation also set all rollbacked packages as "manually installed"? In such case, how to save this package state of "manually/automatically installed" to restore it after the rollback of packages? – Totor Jun 04 '23 at 23:48
  • This does not work. It will only say "Cannot find version" "Cannot find package" – Philip Rego Aug 14 '23 at 02:04
  • apt-history was not found on Debian 11 Bullseye (old-stable). Should the answer be updated? What worked though was what luator mentioned:

    sudo apt-get -s install $(awk '$1 == "2023-08-15" && $3 == "upgrade" {print $4"="$5}' /var/log/dpkg.log | tr '\n' ' ')

    If it complains about unmet deps. or "held broken packages" for some unnecessary or temporarily unnecessary package, you may duplicate that dpkg.log file and remove this package containing lines from the duplicate file and then ran mentioned apt-get install command on that modified file.

    – 16851556 Aug 19 '23 at 09:20
9

The log files /var/log/apt/history.log and /var/log/apt/term.log are the closest things available to your description:

I suppose there could be some kind of script that could save the list of newly installed package and their previous version number

history.log gives a summary list of every action that apt takes in the following format:

Start-Date: 2013-06-21  16:05:05
Commandline: apt-get install rdiff-backup
Install: python-pyxattr:i386 (0.5.0-3, automatic), rdiff-backup:i386 (1.2.8-6), python-pylibacl:i386 (0.5.0-3, automatic
), librsync1:i386 (0.9.7-7, automatic)
End-Date: 2013-06-21  16:05:42

In particular, it gives a list of newly installed packages, or of removed packages. Additionally, term.log shows what actually appeared on the terminal during the action, so that would show the old and new versions of packages. A random sample from my history.log:

Preparing to replace gnupg 1.4.10-4 (using .../gnupg_1.4.10-4+squeeze1_i386.deb) ...
Unpacking replacement gnupg ...
Processing triggers for install-info ...
Processing triggers for man-db ...
Processing triggers for doc-base ...
Processing 1 changed doc-base file(s)...
Registering documents with scrollkeeper...
Setting up gnupg (1.4.10-4+squeeze1) 

Trying to roll back apt automatically is not recommended, but if you use the logs, then it should be possible to do it manually unless the failed action has broken something that interferes with apt's actions, e.g. an inconsistent dpkg database. In that case, you will have to fix the problem before proceeding.

Faheem Mitha
  • 35,108
4

No, apt doesn't make that easy.

The best option is some type of snapshot. Either filesystem snapshots through lvm/zfs/btrfs or instance snapshots if you're using a VM of some kind.

The only other option is to take an inventory of installed packages (dpkg -l) before and after. If you wan to "roll back" you have to explicitly install the previous version.

bahamat
  • 39,666
  • 4
  • 75
  • 104
  • 2
    I know the exact version, but apt refuses: apt install openssl=1.0.2g-1ubuntu4.12 results in E: Version '1.0.2g-1ubuntu4.12' for 'openssl' was not found. I just upgraded to 1.0.2g-1ubuntu4.13 and I'm wondering if that's causing some CORS/CSP problems now – Csaba Toth Jun 27 '18 at 21:14
  • 1
    It may no longer be in the repository. – bahamat Jul 12 '18 at 00:22