The key for our workflow now is (imo) the following settings in gitlab/repository/settings/Merge Requests:
- Merge method: Merge commit with semi-linear history.
You want to use this one because it forces you that before a merge into master, your branch contains the latest master commit. This helps with ordering the commit history in intellij :). - Squash commits when merging: Allow
Some branches dont need to have the history of all the commits, so the branch developer may chose this option in the merge request. It is unchecked by default, but the dev has the option to use it. Use your judgement. - Merge commit message template:
Merge branch '%{source_branch}' into '%{target_branch}'
%{title}
%{description}
%{issues}
See merge request %{url}
I like this template and it helps a lot when you need to track why a change happened. You have title of the MR, description, in which you can give as many details as needed, the jira issues and also the FULL url to the MR. This makes accessing the MR from intellij a click away (in case you want to check the review comments, or whatever).
Now for an example:
Note: this example is about big and interdependent branches where rebasing is a PITA. Smaller branches (in terms of development time, number of commits or number of changes) can do whatever they want.
say you have B1
, B2
, B3
and master
with their dependencies:
B1
depends onmaster
B2
depends onB1
B3
depends onB2
during development, of your branches, always use merge and not rebase:
- merge
master
intoB1
afterwards (or as needed) - merge
B1
intoB2
afterwards (or as needed) - merge
B2
intoB3
this makes your updates (to your upstream branch) much easier than rebasing because all the existing commits are already there the next time you merge. i cannot stress it enough how much easier!
When your branch (say B1
) is ready for review, do the review, do all the fixes, merge master
just like before (if needed), then finally merge your MR into master
without squashing.
It is important to not squash, because B2
and B3
already have almost all the commits from B1
(and master
), so next time you merge master
into B2
, then B2
into B3
you will have much less conflicts to solve (ie. much less friction)
Now continue working on B2
and B3
, merging them into each other as needed.
Key with big branches is:
- use merge
- do not rebase
- do not squash your commits
- do not rewrite your commit hashes
Obviously, if you force push B1
after you already merged B1
into B2
, then you'll have rewritten history, so some conflicts will appear. On the other hand, if you didnt yet merge the "force pushed" changes into B2
, then you're free to do whatever.
It is true the by using merge, you won't have such a nice history, as you'll have all the noise from all the master
/BX
merges, but it makes your development time so much easier.
It remains for you to decide what is more important:
- the rebase approach: having an easy to follow -linear- git history after the merge, or
- the merge approach: having a potentially harder (but not very hard because we're enforcing the Merge method) -non-linear- git history but with a much easier time during development.