Over 10+ years of using Git, I've only ever used git rebase
for very specific cases and most of those uses were at the beginning of my career when I read that it was a good practice to use it.
The most common argument is that it helps reading the Git history. As I've been avoiding rebase
for years now I can tell you that in no situation I found myself being like "oh no I wish this commit was rebased for clarity", it's even quite the opposite. I find it much clearer to see what actually happened rather than a redacted history.
On the other hand, rebases can cause weird and unexpected behaviors. After all you're messing with the git history, which is not the most intuitive thing.
So in the end, who uses rebase and for what reason?
Top comments (5)
I use rebase to pull upstream base branch changes from main branch and merge to merge changes into upstream.
Rebase doesn't mess with history, it preserves it. Feature branch changes not merge in main branch should be on top of latest merge changes, not intertwined with other development commits.
Exactly. It's so tiring to see those discussions of merge versus rebase, when it's the wrong discussion. Rebase and merge complement each other, they are not opposites and there is no "better" way. Yin and Yang to be applied in different scenarios.
Yes, indeed, though the rebase/merge debates I've seen were always in the context of bringing in remote changes.
Pushing changes is a moot point, you can't use rebase for that anyway unless you want to rebase your branch on top of remote and then force push to replace the origin (develop/master/etc) with your rebase version.
But locally, bringing in remote changes by merging develop /master into feature results in not only history cycles impossible to properly track but also prevents using things like interactive rebase to cleanup unwanted commits and resets since all these operations only track history comun from one branch of a merge.
I use
git rebase
when my team is committing to the same branch (as opposed to a branch per feature) and I'm getting ready to push my local commits to my team's remote branch. When there are no conflicts this avoids a commit like "merged with upstream" and when there are conflicts, the commit that resolves them is right next to my other commits around the same feature.There are a lot of articles that try to explain how it works, this one seems pretty good.
I agree that git rebase isn't always needed. I think it depends on every person's git workflow in general. Also, it's not like commit history needs to be perfectly clean to be usable. In fact, in most places where I've worked, commits are an utter mess, with branches ranging from a single huge commit with a message that doesn't describe what the work was, to multiple small commits all having the same commit message.
But everything still works fine. So I agree when you say that it doesn't hurt the work or readability very much. After all, you rarely need to read the commit history of the project. You probably also have a ticketing system to help.
However, for very little effort, I like to have a clean commit history in my code. So I use it as part of my workflow. Here are some areas and reasons for where / why I use it:
Fast forward merges
In the git top 20 list (gitstar-ranking.com/repositories), more open source projects use fast-forward merges than 3-way merges. So it may be necessary to use git rebase for this.
Linear commit history in feature branches
Even when using 3-way merges, I'd rather commit a branch with a linear commit history if I can. But sometimes there are conflicts with the main branch. So you merge the main branch into your branch to resolve them. But this makes the commit history and commit graph messier. Instead, I rebase to keep my branch's history linear.
Pull with rebase
Pulling without rebase can create 3-way merges in your local branch. I find these unnecessary, so I use
git pull --rebase
(actually I've set this as the default behaviour in the git config file).Cleaning up bad commits in feature branches
Sometimes I use rebase for small refactors I do later. For example, if I'm working on a module, I'll have some commit message along the lines of "add module X" or "add function X". In the meantime, I might do some other related work and create more commits. Afterwards, as I'm checking over all of my work, I might do a tiny refactor on module X, such as writing a line of code in a simpler way, or maybe changing the name of a test.
I don't want useless commits for that:
So I rebase to have a single commit message of "add function X".
But, at other times, I don't commit until I've finished my work. In that case, I structure all of the commits properly the first time and don't use rebase.
Also, as part of my workflow, I commit early and often and also use TDD. That way, if I mess up, I can just reset to the previous TDD loop (from 2 minutes ago). I normally just use
git commit --amend
for these temporary commits, to save the effort of having to rebase them later. But sometimes, I end up with a couple of "temporary commits" for various reasons. In that case, I go back and usegit rebase --interactive
to organise them into something sensible.But that's just my experience. What are your thoughts on this? Do you come across little issues like these? If you do, do you ignore them (because, let's be honest, I don't think they're significant), handle them in a different way, etc.?