top button
Flag Notify
    Connect to us
      Site Registration

Site Registration

Conflict is expected in GIT merger, but not detected

+2 votes
801 views

Let's say I have two identical branches: master and topic. In master I remove some code, i.e. function bar(). In topic I do the same (commit) and after some time I realize I need bar() and revert previous commit
with removal.

So I end with master with no bar() and topic with bar() in its original state. When I merge I get code without bar() and no merge conflict (recursive or resolve strategies). Is it possible to detect such situations as conflicts? When bar() is C++ virtual there is no possibility to catch this with compiler.

posted Nov 29, 2013 by Amit Parthsarthi

Share this question
Facebook Share Button Twitter Share Button LinkedIn Share Button

3 Answers

+1 vote

I don't believe so. The problem you're seeing is that by default, git considers only a small set of points for merges: the heads of the two branches and the merge base. So if one side has changed but the other has not, the changed code takes effect. This is not specifically a git problem, but a three-way merge problem in general.

If you rebase instead of merge, then the code ends up the way you want it, but this may or may not be appropriate for your workflow.

answer Nov 29, 2013 by Naveena Garg
+1 vote

You can do something like:

git checkout master
git merge -s ours --no-commit topic
# conflicts, if any, will happen during cherry-pick
git cherry-pick --no-commit ..topic
git commit -m "Merge branch 'topic'"

Which will give you a merge commit as though using "git merge" but it will have restored the bar() function. However, depending on what's happened on the topic branch, you might have to wade through some conflicts that would not happen with a real "git merge" since cherry-pick will replay all the commits from the topic branch that aren't in master. Maybe some day "git merge" will grow a "--cherry-pick" option.

answer Nov 30, 2013 by Luv Kumar
+1 vote

From the perspective of topic there had been no change to the definition of bar(), hence there was no change to contribute to the eventual merge with master.

One way to avoid this kind of problem is to avoid making (or cherry-picking) the same change on different branches, but instead use a merge of a branch with a common base to implement changes needed on
multiple branches.

So, assuming you recognized the need to delete bar() from both topic and master, create a new branch from the merge-base of topic and master and delete bar() in that branch. Then merge this branch into
both topic and master.

If you subsequently decide to revert the removal of bar() on topic then when you decide to merge topic back into master, git will see that the removal branch has been merged into both branches and will
see the subsequent revert on topic as a change that needs to be merged and you will get the result you are looking for.

So, as a general rule of thumb, try to avoid making the same change on two different branches and instead factor out a change needed in multiple places into a separate branch which is then merged into the branches that need iit.

answer Nov 30, 2013 by Majula Joshi
Similar Questions
+2 votes

I am learning, and experimenting. I was experimenting with "git merge", forgot the "--no-commit", and discovered the hard way that aborting the editor that comes up without saving does NOT abort the merge.

And git merge --abort fails, because the merge succeeded.

Git Gui has a way to amend the comment of the last merge, but no way to undo it. I figure this should be simple, but I don't know how.

+2 votes

I tend to accumulate lots of branches as I'd do one branch per feature. When cleaning up, I'd like to
delete all branches, which have been merged.

I could use

 $ git branch -d (which was merged already?) ^C
 $ git branch --merged # let's find out
 ...
 $ # Now run git branch -d with each of the branches.

This kind of question has already been discussed,
http://stackoverflow.com/questions/6127328/how-can-i-delete-all-git-branches-which-are-already-merged
suggests: git branch --merged | grep -v "*" | xargs -n 1 git branch -d

I could think of:

 $ git branch -d --merged # no need to specifiy a branch iff --merged is given with -d
 $ git branch --delete-merged # comes as an new extra option, doesn't clutter other commands
 $ git branch -d keyword-for-all-merged-branches

Before starting such a feature, I'd like to hear input of others.

+2 votes

I am getting some unexpected results from a merge and I'd like to understand why.

I have two commits X and Y that I want to merge.

git merge-base X Y # yields B
git diff B X -- F # is empty
git diff B Y -- F # contains the change I want merged
git rev-list X ^B -- F # is empty
git rev-list Y ^B -- F # contains one commit

git checkout X
git merge Y

fails with fixable merge conflicts on other files, but uses X's copy of F instead of Y's. I was expecting it to use Y's copy of F, since only Y has modified F since B. What could cause this?

+2 votes

In coreboot we try to check for whitespace errors before committing. Of course a pre-commit hook is the way to go, but unfortunately it is not so simple (at least for me) as the following requirements exist.

  1. Only the files actually committed should be checked. That means running git commit -a, abort that and then running git commit some/file should only check some/file for whitespace errors.

  2. There are certain files that are allowed to have whitespace errors. In our case these are *.patch and *.diff files which by design seem to contain whitespace error.

Currently the whole tree is checked, which takes a lot of time. I tried to come up with a patch, but failed so far. Best would be to have

$ git diff --check --only-committed-files --exclude "*patch$"

where I could not find a way for the last to switches.

Currently, I would use

$ git diff-index --cached --name-only $against -- | grep -v patch$

and pass that list to some whitespace check program. Unfortunately that still does not fulfill the first requirement. What am I missing to solve this elegantly?

+2 votes

I posted this question to StackOverflow a while ago but no one answered it so I thought I'd try here.

Let's say I have a file with this content in master:

_____
Line 1
Line 2
Line 3
Line 4 
_____

Now say I create and checkout a new branch called Test. In this branch I change the file to this:

_____
Line 1
Line 2
Line 3 Modified
Line 4 
_____

and I commit this and switch back to master. In master I change the file to:

_____
Line 1
Line 2
Line 3
Line 4 Modified 
_____

and I commit. Now if I merge branch Test into master, I get a conflict.

Why can't git auto resolve this, as those are two entirely independent lines? If I tell git to edit conflicts using BeyondCompare as the difftool, BeyondCompare autoresolves this without even telling the user, since this isn't a real conflict (other merge tools we use at our company do so also). Is there a way to get git to autoresolve these?

I've tried the recursive and resolve merge strategies but neither do it.

It's an issue in our company because there are certain files where multiple developers change lines in close proximity and this causes many unnecessary conflicts when they pull.

...