Lets say I have created a branch F1 from main. This F1 branch has 20 commits in it. I now want to rebase this branch onto main to pick up changes from main
git checkout F1
git rebase -i main
However, I know that almost all the commits on F1 modify a file that has also been modified on main. So in almost all of the 20 commits I am going to have to resolve conflicts.
It seems like a waste of time fixing a conflict in commit 1/20, just for it to then also conflict in 2/20 and 3/20 and so on.
Should I instead rebase F1 from its first commit (1/20) and squash all of the 20 commits into 1? and THEN do the rebase onto main?
i.e something like :
git checkout F1
git rebase -i HEAD~19 (add -squash to the last 19 commits)
git push -f
then
git checkout F1
git rebase -i main
We have some excellent comments on the question, which I will credit and summarize here into an aggregate answer.
As NoDataFound mentioned in a comment:
If you are willing to squash...
As Axnyff mentioned:
If you were planning on eventually squashing your 20 commits into fewer "good" commits anyway, then yes, absolutely do that squash first and then the rebase. If you probably weren't going to squash them, but it doesn't bother you that much if you do, then again, you might as well squash first. Note that if you're using a Pull Request tool that tracks the history of a branch in the PR, then consider creating the PR before rebasing, and then force push your branch after the rebase so that the 20 commits can still be found in the history of the PR. This is one way to preserve history in the PR tool, even though you won't have the history in the repo itself. I do this sometimes when I suspect someday in the future I may wish to see more granularity of the individual commits, perhaps for determining the reasoning behind why a certain change was made that may be harder to determine in a larger squashed commit. Even without the individual commits in the repo, it's easy to go back and look at the PR to see the original list of commits which you could investigate or even checkout locally again.
If you don't want to squash...
If your commits are important enough to keep, even though a linear history is nice, sometimes the benefit of having a linear history is outweighed by the pain to achieve it. This may be one of those cases where you decide to accept a merge commit. As Tim Biegeleisen points out:
That is by far the simplest solution, and even in a strict rebase workflow, perhaps an occasional merge commit from bringing in
mainwouldn't cause too much angst.If you don't want to squash and can't have a merge commit...
If you want to keep your full history and also not have a merge commit, then you'll have to deal with the conflicts. There are some options which may help make the process more efficient. From LeGEC's comment:
Another option is to try using the
-Xoption for resolving conflicts. This will attempt to resolve the conflicts by favoring either "ours" or "theirs". Note: when rebasing, the meaning of "ours" and "theirs" are flipped compared to when merging. If you are mergingmainintoF1then you will haveF1checked out, and as expected "ours" isF1and "theirs" ismain. However, when rebasingF1ontomain, then during the rebasemainis "ours" andF1is "theirs". For example, if you wish to resolve the conflicts by keeping the change onmainfor all the conflicts in the 20 commits onF1, you would use:Note when rebasing you'll also see the terms "incoming" and "current" which are similar to "theirs and "ours". More info here.