Every git user should be familiar with
git merge and
git rebase. Probably the most known command is
git merge since it's the easiest to understand. I personally think that each of these commands has its uses and one should not be used when the other is better suited.
Fears of using git
First off, it is a common belief that merging is simpler than rebasing. It's true. Explaining merge is simple and yet magical, resulting in a two-parent commit. On the opposite, rebase seems like a hacky vintage technique, the likes of patch files upgrades. Rebase is another way to achieve the same goal as a merge, it's just more complicated. Still, rebasing is a way to rewrite history properly, and it's important to keep a clean history.
Why care about history?
It's not only about a branch's content. The
git log is probably one the first places to glance at when embarking on a new project. It's full of information. It tells you what, where and why the codebase was modified.
During a pull request, the
git log along with the diff of each commit can be of tremendous help in analyzing what changes go together and understand why these changes were made.
git logcaptures the intent of each commit.
Some projects are able to use their git history wisely. These projects are able to generate a changelog solely base on their
I'm not fond of blaming since I don't believe in finding a culprit when it comes to code (unless there was a tremendous mistake!). That said,
git blame has its uses. It helps understand why a specific line was modified and added. It can be of precious aid in understanding why it was done this way and when it was introduced.
Having clean commits can also be useful for cherry-picking a single feature in the most simple manner (
git cherry-pick). As well, don't forget that working in a team means that others will have to see your commits and that nothing is more annoying than commits with messages like "next" or "tried to make it work", "wip" or something rude.
There are probably more reasons to keep a clean history than I can think of. Push your reasons in the comments below.
When to merge
There perfectly valid reasons to merge. It depends on your workflow type, so try to see which reasons fit your workflow.
Fast-forward or Merge-commit
There are two ways of merging: fast-forward or merge-commit. Either is acceptable, though if possible, I prefer fast-forward since it doesn't pollute history. Having a merge-commit should be kept for significant events like a release or any other landmark in a project's history. By significant, I do not mean personally significant like "my pull request was accepted".
GitHub recently added a feature to rebase-and-squash before accepting a pull request, thus allowing to keep a clean history, or at least allowing users to have a pull request workflow that is coherent to the project's git workflow.
Merging is great for long-lived branches. Take git-flow workflow for example.
develop is merged into a
release branch, which in turn gets merged into the
master branch. This type of cascading merge is great to indicate important events using merge-commits.
There is an actual meaning to each merge that is done this way. Every merge into the
master branch corresponds to a release into production. The
git log of the master branch clearly indicates all the dates and versions for each release.
When there will be no rebase
This might seem a little odd, but rebasing clearly is a pain when the current branch contains merges. It can sometimes work, but it's usually a mess, and even more with an interactive rebase. Think twice before merging into a feature branch to get the latest updates. It might seem easy, but trust me, the pain will come later, so don't do it!
This statement is true for long-lived branches, but is also true for remote branches. Remember, if a remote branch is rebased locally, there is no choice but to use
git push --force to push it remotely. And there is absolutely no way to know if someone else worked on this branch. Of course, to avoid getting your coworkers mad by erasing their work, please prefer
git push --force-with-lease. I wish this could be a default or at least configurable, but as of today, it still isn't.
When using local branches
Locally, anything goes as you're not stepping on anyone's feet, so if you like to try things out using different branches, merging them any way you like, go ahead and get things done. All there is to know is that history should be cleaned up before pushing (no spaghetti-ball pushing please)
When to rebase
Rebasing should usually be a default when it comes to branching. Keep in mind what I said about
git --force, but if it's your branch and everyone knows it, then it's perfectly fine to push it, whether it be for CI, deployment, or plain backup purposes.
Remember that someone is going to going to read your history. Reading history first comes with a pull request, then directly in the code base, and lastly with a
git blame. So keeping a clean history helps others understand what you did. If you're like me, that also includes your future you, who will curse the old you unless there is a clean history showing your past intent.
Feature branches are a first-class citizen for rebasing. Indeed, features in their smallest form take only one commit on a branch. Imagine the overhead if instead of one commit there comes along a merge-commit? Even more, if the merge-commit is useless since a fast-forward could have been used. Imagine checking the merge-commit to know if there are differences with each parent?
Some feature branches involve a group work and it makes sense to keep track of who did what, especially for
git blame purposes.
GitHub has an alternative to allow a commit to specify co-authors. Even though it's not a git feature, it's nice to have since the co-authors appear in the commit message. Still, one loses the diffs related to a particular author, but the history is cleaner.
TLDR; Presenting a clean history
Before creating a pull request, it's best to check the branch's history. The pull request preview helps in that. It's what the reviewers will look at. So be a friend and help reviewers.
Merge and rebase when used wisely both help in keeping a clean history.
After publishing this article, I spoke at DevoxxFR18 about it. Here is the video (in French).