Before branching and rebasing make sense, you need the core model: what a commit actually is, what "staging" means, and what HEAD points to.
Every commit captures the full state of your tracked files at that moment โ not just the lines that changed. Git is smart about storage internally, but conceptually, think of each commit as a complete snapshot with a pointer back to its parent.
Each circle is a commit; the arrows point to the parent. HEAD is just a label that says "this is where I currently am" โ it usually points to the tip of whichever branch you're on.
When you run git add, you're not committing โ you're telling Git "include this change in whatever I commit next." This is why you can stage some changes and leave others out of a commit, even within the same file.
git add file.txt # stage a change โ draft for next commit git commit -m "message" # turn the draft into a permanent snapshot
This is the part that trips people up. HEAD doesn't represent "the latest commit" in some absolute sense โ it's just a moveable label pointing at whichever commit you're currently looking at. Checking out an older commit moves HEAD backward; making a new commit moves it forward.
Pick any GitHub repo and watch its actual commit/star history over time.
Try the Repo Visualizer โ