'branch1' and 'branch2' are nothing more than commit pointers. They are states of the history of fulfillment at certain points in time. Thus, when combining 'branch2' into 'branch1', git does a bit more than setting up a common ancestor and tries to apply the changes from both trees together.
Take a simple diagram:
branch1 E <- branch2 | / v / A - B - C - D <- master
In the above example, "branch1" indicates the fixation of B and "branch2" points when fixing E This describes more or less the order of operations that you specified above. If you combined 'branch2' into 'branch1', git would find a common ancestor in B , then apply the whole story that exists between B and E to 'branch1', in particular, commits C , D and E
However, you want just E One (bad) solution would be throwing cherries, as you have already determined. A much better solution is to redistribute "branch2" to "branch1", thereby rewriting the history of "branch2" to include only commit E past "branch1":
git rebase --onto branch1 master branch2
This leads to what you are looking for and reads like "rebase branch2", which was originally based on master, on branch1. Note that I left the "branch1" pointer from this diagram for simplicity, and E became E' because its hash hash has changed (as is the case with these diagrams):
E' <- branch2 / / A - B - C - D <- master
You can get a similar effect with git checkout branch2 && git rebase -i B , and then remove the C and D commit from the interactive reboot session.
In my last work, we regularly came across this problem with isolated function branches. Cut at different points in time from the same production branch, they will pull for unwanted changes if they merge without a reboot. As an integration manager, I regularly rewrote my stories to a common point in the past (latest product release), thereby allowing a clean drain all the way. This is one of many possible workflows. The best answer depends a lot on how your team moves the code. In a CI environment, for example, it is sometimes less important that C and D retrieved along with merges like the ones you describe.
Finally, note that if E depends on any code in C or D , this solution will cause chaos in your story when merging 'branch1' (now containing a set of changes to E' ) back to' master '. If your workflow is incremental, and "branch1" and "branch2" interfere with similar functions and files, merge conflicts will occur as a matter of course. In this case, you may need a closer look at your team’s workflow.