Git branching workflow when you have big and interdependent branches

One of colleagues has the following git workflow related problem:

Hi together.

We have one technical problem / chalenge.

I am developing one technical part, that is divided into more tickets (approx 8-10). These tickets partially depend on each other (e.g. in helper methods, classes, etc.) For each ticket there has to be a new branch. After I finish my development in this branch I make a request for a merge request (MR). The MR gets really merged into the master branch only after the code reviewer gave a “thumb up” … this can take as long as few days … up to few weeks.

This poses a big practical problem: until e.g. branch1 is merged into the master, there are branches: branch2 and branch3 which all depend on each other. Apart from that also changes from other developers are influencing the code base and hence from time to time I need to merge the changes from master into the branches branch1 … branch3.

This is really time consuming and hard to manage.

Have You maybe any idea how to optimise this?

Every meaningful idea is welcome :wink:

Here’s the way me and my team work now, along with some explanations. We’re using gitlab:

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 on master
  • B2 depends on B1
  • B3 depends on B2

during development, of your branches, always use merge and not rebase:

  • merge master into B1
    afterwards (or as needed)
  • merge B1 into B2
    afterwards (or as needed)
  • merge B2 into B3

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.