Essentially, git only has one way of tracking history: every commit has zero or more parents. By tracking backwards from a commit to its parents, and their parents, git can determine what commits are in that commit's history.
When you merge two branches, say develop into master, you have three choices:
- If all the commits on master already exist on develop, you can just move the branch pointer of master to match develop, without creating any new commits. This is a "fast-forward merge".
- You can create a new commit which has both develop and master as its parents. All the commits that are in develop's history are now in master's history as well.
- You can "squash" all the differences between the two branches into one commit, with only master as its parent. All the changes from develop will now be on master, but none of the commits that made up those changes are in master's history.
When you next ask to merge the same branches, git will look for commits which exist on develop but don't exist on master. If you took option 3, all those commits you squashed the changes from are still in that category.
The lesson is to only use squash merges on branches you're going to throw away afterwards. For instance, each task you work on can be in a new branch; you start it from the current state of develop (or master, or main, or wherever), squash merge it, and then delete the branch. The next task starts again from develop/master/main, not from the old task branch, so the old commits that you squashed away don't matter any more.
Alternatively (and my personal preference), don't use squash merges. Make each commit meaningful, use git rebase -i and git commit --amend to tidy up stupid mistakes you don't want in your history (being careful to only rewrite history that you haven't shared with other users, or other branches), and then use a fast-forward merge or a merge commit.