Semi linear merge
Asked Answered
P

2

37

I just noticed in Azure DevOps, there's this option called semi-linear merge. I was wondering what it does? Does it come between the merge strategy & rebase strategy (from the name semi-linear)? If so, what are the pros/cons?

enter image description here

Edit: From Microsoft Devblog I believe this option consist of 2 points:

  1. Rebase the feature branch from the master/dev branch
  2. Then merge the feature branch in the master/dev branch

But isn't that the merge strategy?

Putamen answered 13/1, 2020 at 10:4 Comment(0)
N
50

Semi-linear merge
This strategy is the most exotic – it’s a mix of rebase and a merge. First, the commits in the pull request are rebased on top of the master branch. Then those rebased pull requests are merged into master branch. It emulates running git rebase master on the pull request branch, followed by git merge pr --no-ff on the master branch.

enter image description here

Some people think of this as the best of both worlds: individual commits are retained, so that you can see how the work evolved, but instead of just being rebased, a “merge bubble” is shown so that you can immediately see the work in each individual pull request.

Taken from Pull Requests with Rebase

Nebulose answered 13/1, 2020 at 10:8 Comment(5)
wouldn't the newest right blue already contain all the changes (exactly how a rebased version is), so how can yet another new state be created? Doesn't that new state have to have the exact same content as the newest right blue?Smectic
@Smectic Yes. After the rebase a fast-forward merge would be possible, but this forces the merge commit. (For the same reasons you would use --no-ff for a normal merge.)Psilocybin
@Smectic it has the same tree, but different parent commits, and may also have a distinct commit message.Stillhunt
@Nebulose didn't see how/whether it's possible to write you a message on StackOverflow, so I try with a comment: Is there a tool to create such graphic GIF examples for git commits/graph?Shrive
@Shrive Probably there is, this one is taken from the article linked in the answer. And it has quite a few animations already.Nebulose
P
34

Semi-linear merge just adds a rebase to get your branch up to date before completing the merge. If you are PR'ing my-branch into target-branch, it is identical to the following commands:

git fetch
git checkout my-branch
git rebase origin/target-branch
git branch -D target-branch # just in case you have an old version of it locally
git checkout target-branch
git merge --no-ff my-branch

Some Pros and Cons are as follows:

Pros:

  1. The rebase first makes each merge cleaner and easier to trace visually. It also puts all of the changes into the commits themselves, rather than having to track down undesirable side effects in a merge commit, which is usually difficult. Note it's still recommended that developers do a rebase themselves prior to creating their PR, so they can witness any changes that are occurring at that time, and also run their unit tests against the latest version to make sure nothing funky happened. (This is akin to testing a merge commit and running tests before you create a PR, just to make sure the regular merge is still going to work as intended.)
  2. The merge (with --no-ff) forces a merge commit, and this is helpful because each PR contains the list of commits associated with just that PR, enabling you to view the first-parent history which shows all merges into the branch, and easily compare them. Another benefit of forcing the merge commit is that it's easy to revert an entire PR by simply reverting the merge commit, rather than individually reverting every commit that was in the original PR.

Cons:

  • There are some scenarios where you just don't want to use semi-linear merge. A good example is if your source branch has new merge commits in it that you want to retain. In Git Flow, when you merge release into master, or master back into develop you need to retain any of the merge commits from PRs on those branches. The rebase portion of semi-linear merge will rewrite those merge commits, and not only will the "bubbles" be popped, but worse, the commit IDs will be rewritten. This means you won't know for sure if everything in master is currently in develop. There could be IDs that are missing, despite the code being identical. As a rule of thumb, simply don't do a semi-linear merge if the source branch contains new merge commits.
  • After a semi-linear merge, when deleting your local branches you might have to use git branch -D my-branch (instead of lowercase -d) because the commit IDs may have changed. This is barely an inconvenience unless you generally don't remove your local branches right away; if you wait you'll need to confirm that you can really delete it.
  • If your workflow is for developers to rebase onto the target branch before creating their PR, having this option available might make them lazy, since they know it's going to do it for them. Most of the time it isn't a problem, but every once in a while both an automatic merge or rebase will break something, and it's better that they get used to rebasing first to detect it prior to PR completion. Otherwise, in this (admittedly rare) scenario the conflict is automatically resolved and something breaks in your integration branch.
  • If you use signed commits, if a rebase is needed during semi-linear merge the signatures would not be retained (because the commits are re-written). Depending on why you are signing your commits, this may not be an acceptable choice.

Side Note: other tools provide this feature as well:

  • Bitbucket offers the identical merge strategy, and calls it, appropriately, "Rebase, merge".
  • GitLab has used to have a setting for forcing a "merge commit with semi-linear history" however, at the time of this writing AFAIK it is was just a gate on the MR. (Note GitLab calls Pull Requests "Merge Requests". They are the same thing.) With this setting on you have had to rebase it yourself first (which you can do in the UI) and then you complete the MR. Basically it's 2 button clicks instead of 1. Update: This may no longer be possible. Now GitLab has an option for fast-forward only, but I don't know that you can require the check that the branch is up to date and still do a --no-ff merge.
  • GitHub does not support this yet, though people have been requesting it since 2017.

Additional Note: I can't find this documented anywhere, but I have tested and confirmed, that when completing a PR in Azure DevOps, if you choose either "Rebase and fast-forward" or "Semi-linear merge", your PR source branch is re-written before the PR is completed. Normally you would tick the box to delete your source branch after merging and wouldn't care about this, but if you elect to leave that setting unchecked, then it is important to realize your remote branch will appear as "(forced update)" at your next local fetch, if a rebase was required. This could be a Pro or a Con depending on your use case; I would lean towards preferring this most of the time.

Regarding the other tools, with this strategy GitLab forces you to update your branch with a button click, and Bitbucket specifically does not modify the PR branch in its equivalent "Rebase, merge" strategy.

Psilocybin answered 27/8, 2020 at 17:43 Comment(5)
Minor plug, but if you use Github and you want to do semi-linear merge, I wrote a script to do this. It's available at pypi.org/project/git-pr-linear-mergeOina
@WaldoBronchart Which actions does the script perform? (BTW, I think I might prefer the term "semi-linear" for your script, since I think most people associate "linear" with a complete lack of merge commits, such that a the branch is fast-forwarded when merged.)Psilocybin
Yes, I've heard the same comment. I think i'll rename it for clarity. Check the docs for what the script does (basically, rebase + merge, but works around lots of edge cases)Oina
I’m not sure if the first con still holds. git-rebase(1) knows --rebase-merges now. Is that point still in effect? On the other hand, maybe Azure DevOps doesn’t use it… but then that’s a difference between the abstract concept and one particular implementation of it.Jarman
@Jarman It's still applicable, though I think it could benefit from some edits. AzDO doesn't use --rebase-merges, and I don't know of any popular tool with a PR/MR rebase merge strategy that uses that option (by default or even offers it at all). But in addition to losing merge commits you may wish to keep, another time to not use it is when the source branch is a long-lived shared branch, such as the Git Flow examples. That would be true regardless of whether there are merge commits...Psilocybin

© 2022 - 2024 — McMap. All rights reserved.