Is this just about getting the right impedances based on the changed stackup, where in theory all you need to do is adjust trace widths/spacing, or is there more to it than that?
Variants really are just about assembly, not fabrication, so they're not going to help here.
Any time you have to do a lot of branching iteration like this, source control is a good idea. I haven't looked at source control in Altium in a while, but if the project data survives branching, merging, and rebasing (which it might not depending on the file formats and project file structures, idk) then it could be very helpful in keeping functional changes in sync across revisions that have different fabrication changes. In order to really benefit from this, you will have to develop good source control habits and a fair bit of discipline in keeping your commits clean and atomic, just like you would in a similarly volatile source code repository (and just like you should in ANY source control setting, but lots of projects are more forgiving and it's easy to get lazy/complacent). Keeping notes about what changes were made at each revision (especially if you have functional changes in addition to the fab changes) as a supplement wouldn't hurt.
As far as the actual changes, it seems like the best thing you can do within Altium is to really use the design automation tools as much as possible. So make sure that you have net classes defined for anything that needs specific design rules (whether that's for impedance, clearance/creepage, or current handling), and preferably define those net classes in the schematic with directives so that you can see them. Then structure your design rules based on those nets to be as streamlined as possible, and minimize the number of places you need to change parameters. So for example, if you have multiple different impedance targets on the same board, define one net class per impedance instead of different net classes for each interface that requires that impedance, which requires you to resolve fewer classes into design rules than if you had separate classes for each interface.
There are some things you can do in the initial design phase to make this easier on yourself, like leaving some extra space in the routing to move things around when you need to change trace widths/spacings. If everything is crammed together as tightly as possible then there's more work required to make an adjustment and more opportunity for error. With all of your rules set correctly, adjusting to a new stackup should just(
) be a matter of updating the rules, running DRC, and then fixing the errors one by one. If you've got a pretty roomy layout, you might be able to use a filter to select all the tracks in a given net class and adjust the width in one go, at least for single-ended tracks. If you need to change diffpairs, I think you'll need to reroute those manually since once they're routed they're just normal tracks, so you can't just change the spacing like you can change the width.