You will avoid a lot of problems if you let your Ubuntu system's built-in tools keep your Ubuntu system up to date.
For cases like yours, where that simply isn't possible, best practice is to keep your custom/project environment in a Virtual Machine or a Container. That way, your customizations don't cause conflicts and other problems on your base system.
To stop normal upgrades:
- Disable Unattended Upgrades in
/etc/apt/apt.conf.d/20auto-upgrades. Warning: Your system will no longer receive security patches.
- To keep a few packages unchanged for a limited time, you can
apt-mark hold <packagename>. Over time, your system may diverge from standard Ubuntu, so try to keep that delta small.
- [Optional] Disable Software Updater by uninstalling
update-manager. Warning: This will also remove several desktop metapackages. Under some conditions, this may make your entire desktop stack eligible for accidental autoremoval.
Downgrades are sometimes possible using apt (specify the version that you want), but not recommended. A Debian-based system can have only one version of a package installed at any time, so if you try to downgrade a package that other parts of your system also depend upon, you may get unexpected or painful results. Also, Debian archives usually have only one version (the latest), so you will need to locate the older version yourself.