Code Complete 2 is kinda the bible on disciplined software engineering practice. That's a good start.
Other than that - there is not that much theoretical basis. The core principle is that software engineering is about dealing with a situation where you have far too many variables to fit into a single persons working memory, and how to organize a group of people in a way that they can co-operate without turning the thing into a mess, really fast.
It's more about having a set of understood processes, rather than what those processes really are, so that people can communicate about and co-ordinate their work effectively. Of course the processes need to make sense, but there's no "silver bullet" process that either would fix everything, or, conversely not following would lead to the end of the world.
"Issues like testing / mocking"
Testing has sadly developed bookish dogma around itself. But it's extremely practical. The most important automated test is the high-level integration testing - will this and that work when the customer uses it.
Unit test are about creating enforceable rules to the production system, which makes thing break faster, and, hence, faster to fix.
You don't want someone else to accidentally to break your code - especially that kinda weird cornercase? Write a test - now the rule becomes enforced as a part of your domain model.
" code review,"
Same principle as in writing text. Having someone proofread the things you write generally improves the quality. No need to be dogmatic.
The second aspect is the zenlike increase in code quality. People know that their work will be looked at by someone, hence they have a higher intrinsic motivation not to fudge things.
"management of dev / stage / prod workflows"
The only thing that matters there is that there is one agreed process inhouse. Otherwise things turn really messy, real fast. It's kinda tricky to wrap ones head the first time around the ramifications of the chosen rules, so that's why there are lot of published ways of working .
"the judgment / taste required to make maintainable changes to a million LOC repository,"
"Working effectively with legacy code" by Michael C. Feathers is a good start. Now, if the corpus of code has a thorough integration and unit test suite, you can change things, and if you accidentally break something, the tests will tell you.
If there are no tests, then, better start writing them. You can't do any large scale modifications - especially to production code - without them.
Have some tool that automatically tells you the test coverage.