In most workflows, the owner of each feature branch is responsible for keeping their branch up to date with whatever the "official" line of code is (To be as generic as possible, I'll call the integration branch master, though it can be develop, release, or other name in various workflows). So the full sequence for your scenario would look like this:
- Developer 1 starts fb1 from master
- Developer 2 starts fb2 from master
- Developer 1 completes his feature and submits pr1 to merge fb1 into master
- fb1 is tested and approved and pr1 is accepted, master is updated to contain initial + fb1
- Developer 2 completes her feature but finds her branch is now out of date
- Developer 2 merges master into fb2 and resolves the conflicts her branch now contains initial + fb1 + fb2
- Developer 2 submits a pr2 to merge fb2 into master
- A serious bug is found resulting from feature1, so the merge of fb1 to master is reverted and master now contains initial only
- fb2 is now out of date because master has been altered and if there were conflicts resolved before, they will occur again with the original code restored so that pr2 will not be able to automatically merge and bitbucket will warn you.
- Developer 2 merges master into fb2 and resolve the conflicts, making her branch contain initial + fb2
- Developer 2 pushes to update pr2 which is then approved and merged, resulting in a master branch that contains initial + fb2
Git uses the most recent common ancestor of two commits when merging, not the original point where the code diverged. Even if there were no conflicts, when the changes from master including fb1, are integrated into fb2, the common ancestor between those two branches would be a point on master containing initial + fb1, if fb1 was subsequently removed from master, git would see those changes had occurred on the master branch and the resulting merge would not contain those changes.
You can think of a merge algebraically, where m = merge
, b = base
, l = left
, r = right
, f = feature
and i = initial
m = b + diff(b,l) + diff(b,r)
m = (i + f1) + diff((i + f1), (i)) + diff((i + f1), (i + f1 + f2))
m = (i + f1) + (-f1) + (f2)
m = i + (f1 + -f1) + (f2)
m = i + f2