The list of installed packages *is* in `/var/lib/dpkg/status`; that is the canonical reference. Installed packages are signalled in that file by their “install ok installed” status.
If you only want to track a list of installed packages, you can run
dpkg --get-selections
periodically and store its output in a file tracked with `git`; since you also want versions,
dpkg -l
might be more suitable.
As pointed out by [Martin Konrad](https://unix.stackexchange.com/users/235891/martin-konrad), you should also track the manually-installed markers, and I’d add the holds too:
apt-mark showmanual
apt-mark showhold
You could add all the above to a `dpkg` hook, to track all changes to your system; for example, using `/etc/packages/` to hold the files (rather than `/var/lib/dpkg`, which is “owned” by `dpkg` and should be left as-is), create a file named `/etc/dpkg/dpkg.cfg.d/package-history`, containing
post-invoke="if [ -x /usr/local/bin/package-history ]; then /usr/local/bin/package-history; fi"
and a file named `/usr/local/bin/package-history` containing
#!/bin/sh
cd /etc/packages
dpkg --get-selections > selections
dpkg -l > list
apt-mark showhold > holds
apt-mark showmanual > manual
The latter needs to be executable:
sudo chmod 755 /usr/local/bin/package-history
The outputs of all the commands above are sorted, so there’s no need to post-process them. With those files, you’ll be able to restore the installed package states exactly, track version changes, and also see packages which have been removed but not purged.
You can either add `git commit` (checking for changes first) to the `package-history` script, or use `etckeeper` to track changes to the files in `/etc/packages`, or even make `/etc/packages` a git repository itself. Using a `dpkg` hook ensures that the files will be updated with *any* package change, whether driven by `apt` or `dpkg` or any other tool piggy-backing on top of `dpkg`. If you commit in the `package-history` script itself, then the commit granularity will correspond to `dpkg` executions; if you rely on `etckeeper`, it will correspond to actions involving `etckeeper`.
To handle the commit in the script, add
if [ "$(git status --porcelain | wc -l)" -gt 0 ]; then
git add *
git commit -m 'Update package information'
fi
to the end of the script above.