Merging between version branches - noobaa/noobaa-core GitHub Wiki

Once we create a version branch, let's say 2.0, and keep pushing commits to that version branch, and in the meanwhile more commits are added to master.

This wiki describes how to forward merge changes from 2.0 to master.

Apparently the solutions that avoid repeating conflict resolution is either merge or cherry-pick. Using rebase will inherently force to repeat conflicts on every rebase.

Cherry-picking - Preferred!

# fetch and update branches from origin
git fetch origin master:master 2.0:2.0

# create new branch from master
git checkout -b guy-cherry-from-2-0 master

# get list of commits to cherry pick (see https://git-scm.com/docs/git-cherry)
# every line with '+' should be picked, lines with '-' are already in master
git cherry -v HEAD 2.0

# cherry-pick commits from 2.0
git cherry-pick <commit-hash-1>
...
git cherry-pick <commit-hash-n>

# manually resolve conflicts for each commit ...

# push and PR
git push

Arrow

Creating an "Arrow" in source control means to mark the current state of two branches as if they are merged, even if they are not in terms of git.

From https://git-scm.com/docs/git-merge#_merge_strategies: ours This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. It is meant to be used to supersede old development history of side branches.

In order to mark a branch merged to another branch we can do a pseudo merge with the "ours" merge strategy like this:

# fetch and update branches from origin
git fetch origin master:master 2.0:2.0

# create new branch from 2.0
git checkout -b guy-arrow-from-2-0 2.0

# merge by "ours" strategy will add the missing commits to the history but will not change the master head
git merge -s ours 2.0

# push and PR
git push

Using merge

While this method works pretty easily, merges behave a bit weird as the commits that merge brings are pushed in the middle of the commit stream and a final "merge commit" is created in the end to fix any automatic merging or manual conflicts. This is why we prefer to use cherry-picking instead, but merge will work too.

# fetch and update branches from origin
git fetch origin master:master 2.0:2.0

# create new branch from master
git checkout -b guy-merge-from-2-0 master

# merge that branch from 2.0
git merge 2.0

# manually resolve conflicts for the entire merge ...

# push and PR
git push

What doesn't work?

We tried to do it using a standard rebase as follows:

# fetch and update branches from origin
git fetch origin master:master 2.0:2.0

# create new branch from 2.0
git checkout -b guy-merge-from-2-0 2.0

# rebase that branch from master
git rebase master

# manually resolve conflicts per commit ...

# push and PR
git push

This method seems to work well for the first time, and all the commits from 2.0 are re-created on master, so they have different commit hashes.

However, when there are resolved conflicts and this method is repeated the problem is that git does not identify those commits on master as resolved conflicts, and the next rebase will ask to manually resolve the same conflict again without any real diff to apply.

Even starting with a merge, and then use rebase in order to remove all duplicated commits, the result is the same as the simple rebase option that repeats conflicts.

# fetch and update branches from origin
git fetch origin master:master 2.0:2.0

# create new branch from master
git checkout -b guy-merge-from-2-0 master

# merge that branch from 2.0
git merge 2.0

# manually resolve conflicts for the entire merge ...

# rebase the merged commits on top of master
# this will remove unneeded commits and potentially also the merge commit
git rebase master

# push and PR
git push