Whether working in trunk-based style or feature-branch style, the main (or trunk, also known as master) branch, along with any release branches if doing that thing, SHOULD NOT have merge-commits.
I do not like to see merge commits in the main/trunk branch. I prefer a straight, unblemished history line.
* d589966 -(17 hours ago) (HEAD->main, origin/main,origin/HEAD)
* 5f3c420 -(17 hours ago) Merge branch ‘main’
| * 4650c10 -(17 hours ago)
| * ae51497 -(17 hours ago)
| * b45fa11 -(18 hours ago)
* | d532336 -(17 hours ago)
* 3d7bb50 -(18 hours ago)
* 6851949 -(18 hours ago)
* 28a191b -(19 hours ago)
* 01f6be2 -(19 hours ago)
Merge commits make reviewing the history more difficult for humans and source control tools to understand, explore, and resolve issues. Other than the visual part, they introduce complexities to reverting any issues that come up which cross the merge-commit line.
I have these settings in my global
.gitconfig to fail any merges that are not fast-forward. This forces me to resolve those with a proper rebase before merging into main.
ff = only
ff = only
The workflow I use to resolve such problems is:
- Create a branch at the current state
git branch wip
- Reset the
mainbranch upstream head either by resetting it then pulling or fetching then resetting it.
- Change to the
git checkout wip
get rebase main(resolve any merge conflicts the usual way)
- Change to the main branch
git checkout main
- Merge the
wipbranch into main (since it will fast forward now)
git merge wip
- Delete the
git branch -d wip
As with anything that I do more than a couple of times, I have automated this workflow. The scripts below are in the set that I source into my current terminal. When I
git pull and it fails because it cannot fast forward (see the
.gitconfig settings above), I can just
The script stops at the rebase step if there are merge conflicts to resolve. I use the normal
git mergetool and
get rebase --continue to handle those and then
repo_wip_merge to finish up.
Note that when there are no merge conflicts,
repo_wip_rebase does all the work.
git checkout main || return $?
git merge –ff-only wip || return $?
git branch -d wip || return $?
git branch wip || return $?
git reset –hard origin/main || return $?
git checkout wip || return $?
git rebase main || return $?
# if there are merge conflicts, it stops here. Resolve them and then do this separately
It is possible to do this as get aliases instead so that the commands might be:
I tend not to create git aliases for two reasons. The most important is to keep custom stuff clearly custom. I do not want to get in the habit of using
git xx short cuts and erode my memory of the raw git commands. Having scripts with the prefix
repo_ makes it clear to my brain that this is a custom thing. The second reason is that having these in a script separate from my home folder that is under source control is easier for me to manage.
I know there are other options for both of these. This is what works for me.
I hold no strong opinions on how you should automate your work. I only hold that you should automate as much as you can in whatever way works for you.