Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

git: merge two branches: what direction?

We have the following situation:

             A --- B --- C --- ... --- iphone            /   ... --- last-working --- ... --- master 

Between last-working and iPhone, 32 commits were made. Between last-working and master, a lot of commits were made.

What I want now is a new branch where I have iphone and current master merged together. And at some later time, this should be merged into the master.

First, I planned to do:

git checkout iphone -b iphone31 git merge master 

But then I thought, if it would be better to do:

git checkout master -b iphone31 git merge iphone 

Now I am wondering. What would be the difference in the result? Would the merge behave different?

I already tried both and as I have expected, I got many conflicts because iphone is really old compared to master. Now I wonder about the easiest way to merge them.

Maybe even starting with master and merging each single commit of iphone into it would be easier? Like doing this:

git checkout master -b iphone31 git merge A git merge B git merge C ... git merge iphone 

At the very end, when this merge is done (i.e. all conflicts are resolved and it is working), I want to do this:

git checkout master git merge iphone31 
like image 478
Albert Avatar asked Feb 28 '10 12:02

Albert


People also ask

Does it matter which way you merge git?

Usually it does not matter if both branches are topic or feature branches. However, if you have an integration branch or a branch that marks what's been published, you definitely want to use the long lived integration branch as the one that's checked out and merge the other one into it.

What happens when we merge two branches?

When you perform a merge, you effectively merge one branch into another—typically a feature branch or bug fix branch into a main branch such as master or develop. Not only will the code changes get merged in, but also all the commits that went into the feature branch.

Which strategy is used by get for merging two branches?

Recursive is the default merge strategy when pulling or merging one branch. Additionally this can detect and handle merges involving renames, but currently cannot make use of detected copies. This is the default merge strategy when pulling or merging one branch.

Does merge order matter?

The only difference that comes from merging order should be the order of the parents of the merge commit.


2 Answers

Regarding the alternatives

git checkout iphone -b iphone31 git merge master 

and

git checkout master -b iphone31 git merge iphone 

they will have identical ease or difficulty, it is like arguing whether a glass is half full or half empty.

Version tree perception

How we look at version trees are in some way just our arbitrary perception. Let's say that we have a version tree like the following:

    A----------+     |          |     |          |    \_/        \_/     B          X     |          |     |          |    \_/        \_/     C          Y     |     |    \_/     D     |     |    \_/     E 

And let's say that we want to make a new version Z checked out from Y based on the changes from C to E but not including the changes made from A to C.

"Oh, that will be difficult because there is no common starting point." Well not really. If we just place the objects a little differently in the graphical layout like this

      /     C+---------+     | \        |     |          |    \_/         |     D          B     |         / \     |          |    \_/         |     E          A                |                |               \_/                X                |                |               \_/                Y 

now things are starting to look promising. Notice that I have not changed any relation ships here, the arrows all point the same way as in the previous picture and version A is still the common base. Only the layout is changed.

But it now trivial to imagine a different tree

    C'---------+     |          |     |          |    \_/        \_/     D          B'     |          |     |          |    \_/        \_/     E          A                |                |               \_/                X                |                |               \_/                Y 

where the task would just be to merge version E normally.

So you can merge anything you want, the only thing that influence the ease or difficulty is the aggregate of changes done between where you select as a starting point or common base and where you merge to. You are not limited to using the natural starting point the your versioning tool suggest.

This might not be simple with some version control systems/tools, but if all else fails there is nothing that stops you from doing this manually by checking out version C and save the file as file1, checking out version E and save the file as file2, checking out version Y and save the file as file3, and run kdiff3 -o merge_result file1 file2 file3.

Answer

Now for your specific situation it is difficult to say exactly what strategy that will produce the least amount of problems, but if there are many changes that create some kind of conflict it probably is easier to split up and merge smaller parts.

My suggestion would be that since there are 32 commits between last-working and iphone, you could for instance start by branching of master and then merge in the first 16 commits. If that turns out to be too much trouble, revert and try to merge the 8 first commits. And so on. In worst case you end up merging each of the 32 commits one by one, but it would probably be easier than having to handle all the accumulated conflicts in one single merge operation (and in that case you are working with a really diverging code base).

Tips:

Draw on paper a version tree and note with arrows what you want to merge. Cross off things as they are done if you split up the process in several steps. This will give you a clearer picture of what you want to achieve, what you have done so far and what is left.

I can really recommend KDiff3, it is an excellent diff/merge tool.

like image 189
hlovdal Avatar answered Sep 23 '22 11:09

hlovdal


There is a difference.


Always check out the target branch during a merge (i.e. if merging A into B, checkout B).


Folks often say that the merge direction does not matter, but this is wrong. While the resulting content will be the same regardless of the merge direction, there are several aspects that are different:

  1. The diffs listed in the resulting merge-commit will be different depending on the direction.
  2. Most branch visualizers will decide which branch is "primary" using the merge direction.

To elaborate, imagine this exaggerated example:

  • You branched off from MASTER at 1000 commits behind, and named it DEVELOP (or in a tracking-branch scenario, you have not fetch for quite some time).
  • You add one commit into DEVELOP. You know there are no conflicts for this change.
  • You want to push your changes into MASTER.
  • You incorrectly merge MASTER into DEVELOP (i.e. DEVELOP is checked out during the merge). Then, you push DEVELOP as the new MASTER.
  • The diffs in the resulting merge-commit will show all 1000 commits that happened in MASTER, because DEVELOP is the reference point.

Not only is this data useless, it's hard to read what's going on. Most visualizer will make it look like your DEVELOP line was the primary all along, with 1000 commits brought into it.

My suggestion is this: Always check out the target branch during a merge (i.e. if merging A into B, checkout B).

  • If you are working on a parallel branch and want to periodically bring in changes from a main branch, then checkout your parallel branch. The diffs will make sense -- you will see the changes done in the main branch w.r.t to your branch.
  • When you are done working in parallel and wish to merge your changes into the main branch, checkout the main branch and merge with your parallel branch. The diff again will make sense -- it will show what your parallel changes are w.r.t to the main branch.

The readability of the log, in my opinion, matters.

like image 38
Ryuu Avatar answered Sep 20 '22 11:09

Ryuu