I had an interesting thing happen using git, wondering if anyone could explain it to me so I can understand better.
When doing a merge of multiple branches (A,B),
git merge A B
fails as non-fast-forward, while
git merge B A
worked well. Why would that be?
Let's assume that A is a strict, direct child of the current branch. Then assume that B is a strict, direct child of A.
The octopus merge, which processes heads given as arguments from left to right, incrementally with respect to the tree, but independently with respect to the index succeeds without conflict if it tries to apply B and then A, but encounters a conflict if it does the convert.
As per the git-merge
manual, section MERGE STRATEGIES:
octopus This resolves cases with more than two heads, but refuses to do a complex merge that needs manual resolution.
For instance:
~ $ git init testdir && cd testdir && echo "This is C" > myfile Initialized empty Git repository in /home/huitseeker/testdir/.git/ ~/testdir $ git add myfile && git commit -m "C" [master (root-commit) f0c8c82] C 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 myfile ~/testdir(master) $ git checkout -b "A" && echo "This is A1" > myfile Switched to a new branch 'A' ~/testdir(A) $ git commit -m "A1" myfile [A ac5b51c] A1 1 files changed, 1 insertions(+), 1 deletions(-) ~/testdir(A) $ git checkout -b "B" && echo "This is B1" >> myfile Switched to a new branch 'B' ~/testdir(B) $ git commit -m "B1" myfile [B 5bc838c] B1 1 files changed, 1 insertions(+), 0 deletions(-) ~/testdir(B) $ git checkout master Switched to branch 'master' ~/testdir(master) $ git merge B A Fast-forwarding to: B Already up-to-date with A Merge made by octopus. myfile | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) ~/testdir(master) $ git reset --hard HEAD^^^ HEAD is now at f0c8c82 C ~/testdir(master) $ git merge A B Fast-forwarding to: A Fast-forwarding to: B error: Entry 'myfile' would be overwritten by merge. Cannot merge. Merge with strategy octopus failed. ~/testdir(master) $ cat myfile This is A1
Indeed, when fast-forwarding to A, the label of master has not been pushed forward, though the tree has.
~/testdir(master) $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: myfile #
If, looking at the code of what the octopus merge does, I perform this manually (look above for hashes):
~/testdir(master) $ git reset --hard f0c8c82 HEAD is now at f0c8c82 C ~/testdir(master) $ git read-tree -u -m f0c8c82 ac5b51c ~/testdir(master) $ git read-tree -u -m f0c8c82 5bc838c error: Entry 'myfile' would be overwritten by merge. Cannot merge.
In the other direction (merge B A
), now, if you look again at the code of merge-octopus, it tries to detect the branch we are trying to add is already in the tree (second case
of the for
loop). Indeed, at the merge of A, it sees ac5b51c (a.k.a. A's head) is the common ancestor of A and B, and aborts without doing the second read-tree
.
This behavior is consistent with the fresh version of git : though I've pointed to v.1.3.1, this is still happening with my version.
~/testdir(master) $ git --version git version 1.7.5.4
tl;dr : you want your octopus merge branches to touch distinct files
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With