How exactly does bitcoin code change happen in a decentralized system I have long been under the assumption that bitcoin was just a &quot;protocol&quot; or a &quot;contract“. Different nodes run their own implementation, on different hardwares. Some are efficient, some not, and they have to agree to the bitcoin protocol to function in this ecosystem.
But I found out there is actually a centralized bitcoin code base that's frequently updated! How do they even ensure that every nodes update to the newest code? And how do they ensure that the code compiles for every single hardware? Or, I guess most imporantly, were there any backward incompatible changes in the history that require every node to update?
I have long been under the assumption that bitcoin was just a &quot;protocol&quot; or a &quot;contract“. Different nodes run their own implementation, on different hardwares. Some are efficient, some not, and they have to agree to the bitcoin protocol to function in this ecosystem.

That's correct. There are dozens of implementations of nodes, wallets, and various other pieces of software that speak the P2P protocol.
There are optional features, and new things that get added to the protocol, but these are almost exclusively done in a compatible way: negotiated between peers that support them, and falling back to older alternatives between peers that don't.
Part of this is negotiated through the protocol version, which used to be just the version number of the Bitcoin client, but since Dec 2011 these are separate.
Most Bitcoin protocol implementations these days are compatible back as far as the Bitcoin 0.2.10 release (from June 2010, a time when there was just a single implementation), when checksums were added to the protocol. Using a protocol adaptor (a node that speaks both the old and new version), software written today can even speak with the very first code (Bitcoin 0.1.0, January 2009).

But I found out there is actually a centralized bitcoin code base that's frequently updated!

Bitcoin Core is a project that maintains an implementation that is an evolution of the original codebase by Satoshi. It is often called a reference implementation, and a focal point for development. However, it is not the only implementation, not even the only fully validating node implementation, and it does not decide what the protocol rules are (though there are some optional protocol features that are only implemented in Bitcoin Core).

How do they even ensure that every nodes update to the newest code?

They don't; strictly speaking there is no need. The protocol rules and rules about which blocks are valid don't really change. There are good reasons to update (e.g. security improvements, speed improvements, new features), but that's anyone's individual choice. Bitcoin Core very deliberately does not have an auto-update feature, as that is deemed to give too much control over the network by the client's maintainers.

And how do they ensure that the code compiles for every single hardware?

Extensive continuous integration testing. All code changes are tested on a variety of platforms, including Windows, MacOS, Linux (for ARM32, ARM64, x86_64, RISC-V, POWER), and since recently also Android. More systems may work, but are not guaranteed to.

Or, I guess most imporantly, were there any backward incompatible changes in the history that require every node to update?

Yes, but they are very rare (and ancient history by now).
Bitcoin 0.2.9 (protocol version 209) introduced checksums in every protocol message. Initially these were negotiated, like very other protocol feature. However, Bitcoin 0.2.10 (June 2010), the feature was implemented so that as of February 2012, the checksum would become mandatory - and included in the messages used for negotiating versions themselves. This meant that by February 2012, node software before 0.2.9 stopped working.
Another source of incompatibility is the network's consensus rules. These are the rules that determine which transactions and blocks are valid, and the most complicated part of the system. The entire network has to effectively implement them identically, or there is a risk that the network splits into separate currencies. There are many questions on this site on this topic, if you want more information, but the short summary is that almost all changes to these rules are now done as so-called &quot;soft forks&quot;: rules that only tighten which blocks are valid, which implies the network is safe from splits as long as a majority of the hashrate also enforces these rules. Other changes are called hard forks, and apart from an debatable one in 2013 (due to a change in the database layer, see BIP 50), there have not been any of these since August 2010. For more information, see https://blog.bitmex.com/bitcoins-consensus-forks/.
Disclaimer: I'm a contributor and maintainer for Bitcoin Core, and have been involved in some of the changes mentioned. The protocol 209 checksum change was before my time.