Software engineering includes the process that turns a local edit into a safe change in a running system. Every stage should provide evidence that the next stage can use: a reviewable diff, repeatable tests, a traceable artifact, and signals that show how the deployed version behaves.
Version the change
Git stores content as objects and builds commits from a tree plus metadata and parent links. A branch is a movable name for a commit, so creating a branch is cheap; merging combines histories and may require resolving conflicting edits. A commit records a snapshot, but it does not prove that the code is correct or deployable.
Test at the boundary that matters
Unit tests check small logic quickly. Integration tests exercise interactions with real or controlled dependencies. Contract tests verify assumptions between independently developed components. End-to-end tests cover a user journey but tend to be slower and more sensitive to environment. Choose a portfolio that catches likely regressions without making feedback too slow to trust.
Build once, release deliberately
Continuous integration can run formatting, static checks, and tests on each change. A build produces an artifact that should be identified by an immutable version or digest. Deployment strategies such as rolling, canary, or blue-green change how traffic reaches that artifact and how quickly a release can be stopped. A rollback is useful only if the prior version still works with current data and dependencies.
Observe what users experience
Logs give event detail, metrics show trends, and traces connect work across boundaries. Alerts should point to user impact or a clear operational action. After release, compare production behavior with the expected result and keep a path to disable or reverse risky changes.
Pro Git explains Git's data model; Google's Site Reliability Engineering book connects release practices to operating services.