I like using explain git with D3 to show how things work - https://onlywei.github.io/explain-git-with-d3/#rebase
Compare that with merge - https://onlywei.github.io/explain-git-with-d3/#merge
At the end, the HEAD has the same content, but the structure of the graph is different.
Note that rebase falls in the set of "rewriting history" operations in git and so pay attention to the caveat in the explanation:
> For this reason, you never want to rebase commits that have already been shared with the team you are working with.
Rebase and reset are two of the commands that need to be done with caution and full awareness if working with commits that have been shared with other people.
You can use `git rebase` to perform the so-called "squash" action, that squashes multiple commits at once.
For example, the latest commits in the branch look like this:
123 WIP1
456 WIP2
789 WIP3
012 FeatureA
WIP1,2,3 as commits should be merged into a single Git commit, and be put on top of the FeatureA commit - so to speak, use the FeatureA commit as a new base.
Git uses the rebase command to do exactly that - you'll perform an interactive rebase onto FeatureA commit. The interactive rebase allows you to define specific actions.
"pick" keeps the commit. In order to perform a squash of the WIP1,2,3 commits, you'll keep the first WIP1 commit, and tell Git to continuously squash the next commits WIP2 and WIP3. Each operation is done at once.
pick 123 WIP1
squash 456 WIP2
squash 789 WIP3
pick 012 FeatureA
This results in a new history and commit - squashing changes the commit sha checksum, with new content in the Git commit, as well as a new base commit.
567 Squashed
012 FeatureA
"squash" in an interactive rebase keeps the individual commit messages for each commit, and at the end, the editor for commits allows you to edit the final messages. This can be helpful to review the squash action, and for example amend or abort it.
If you plan to not keep the individual commit messages, "fixup" throws them away and can be used as alternative action.
"git rebase -i" has more options - you can also stop at a specific commit, and amend it, e.g. when a "git add" was missing a file earlier.
Note: Any change to a commit within the Git history forces all later commits to change too, as the linked commit base changes too, thus regenerating the sha checksum. This entirely rewrites Git history trees, and can be very invasive - if you intend to keep specific commit IDs (for release tags for example), ensure that the workflows to not allow rebasing on certain branches. One possible workflow is to keep the main default branch protected, disallowing to rebase and push a changed history, add git tags there, and only rebase in a Merge Requests branch prior to review/approve/merge cycles.
Moving from Git commands to GitLab - GitLab also offers a Merge Request option to squash commits automatically when the MR is accepted, so that all commits in the MR branch are squashed, and you don't need to do it manually. https://docs.gitlab.com/ee/user/project/merge_requests/squas...
Last but not least - the quick action /rebase in a MR comment allows to trigger a rebase via the UI too, thus not requiring client side clone/fetch/rebase. More tips in https://about.gitlab.com/blog/2021/02/18/improve-your-gitlab...