Version control is a way of documenting how something got made. That covers more than the code. It covers your configs, your docs, your scripts, and the weird one-off thing you wrote at 2am. If it's part of how the thing got built, it belongs in source control.
This matters so much in programming because programming is endlessly iterative. You don't write code once and walk away; you change it, break it, fix it, rethink it, and change it again. Every line ends up as the result of a hundred small decisions, and by the time someone reads the final version, most of those decisions are invisible.
The history and the reasons behind the code are where the real value is. Why is this function written in such a strange way? The commit history shows it was a workaround for a bug in a dependency. Without that trail, the code just looks wrong, sloppy, as if nobody meant it.
Software keeps changing, and every change adds a little disorder. Each change is made by someone solving one problem, under a deadline, who can see only part of the system. The fix works, but it bends the design a little away from what it was built for, adding a special case or a new assumption that the rest of the code doesn't know about. One bend is harmless. A thousand of them, made by dozens of people who never talked to each other, turn into a structure nobody designed.
Code like that, with no history attached, rots, and I mean that literally, as entropy. It gets harder and harder to understand, until eventually nobody wants to touch it, because nobody knows why it does what it does.
Picture a billing service with a three-second sleep in the middle of the payment flow. Everyone agrees it's ugly, but no one knows why it's there, and the person who added it left years ago. So it stays, and new code grows around it, padded with defensive checks against problems no one can name. Then someone finally runs git blame on that line and finds a commit message: "Payment processor returns stale status if polled within 3s of charge. Remove once they fix it." It turns out the processor fixed it two years earlier. The sleep comes out, and so do the defensive checks.
Good version history is a map of how that kind of complexity built up, and of the tradeoffs made along the way. Each commit is a small note to the next person, who will often be you, saying what changed and why.
So commit everything. And in every commit message, explain why you made the change.
The common pattern versioning is Semantic Versioning, or SemVer.
A usual software version number looks like this:
v1.4.2The core version is:
MAJOR.MINOR.PATCHWhat each segment means
1 = MAJOR version
This changes when you make a breaking change.
Example:
1.4.2 → 2.0.0Meaning: “Be careful. Something changed that may break old users.”
4 = MINOR version
This changes when you add a new feature, but old users are still safe.
Example:
1.4.2 → 1.5.0Meaning: “New functionality was added, but existing usage should still work.”
2 = PATCH version
This changes when you make a bug fix or small safe change.
Example:
1.4.2 → 1.4.3Meaning: “Same product, same behavior, just fixed.”
Extra segments you may see
Pre-release
1.4.2-beta.1This means: “This is not final yet.”
Common examples:
1.4.2-alpha1.4.2-beta1.4.2-rc.1rc means release candidate. It is basically saying, “We think this might become the final release, unless we find problems.”
SemVer treats pre-release versions as lower than the final release, so:
1.4.2-beta.1 < 1.4.2