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.