0

I get a merge conflict in index.js when running this:

$ git checkout feature
$ git merge master

The feature branch index.js

const a = 1;
const b = 1;

The master branch index.js (This is where feature branch was born)

 const a = 1;

The master branch index.js (Current state)

 const a = 2;

I want automatically resolve the conflict in such a way so that index.js on feature branch was updated to this:

const a = 2;
const b = 1;
manidos
  • 3,244
  • 4
  • 29
  • 65
  • 4
    Right! We would all like to have that..... but git can't do it.... nor any other decent VCS. Merging engines can't just guess how to put code together... they try their best and, given your two tips of the branches (can't see the common ancestor, right?) you will get a conflict. – eftshift0 Apr 04 '19 at 14:41
  • 1
    perhaps `git rerere`can give you a little hand? I have never used it myself so can't really tell how to use it. https://git-scm.com/docs/git-rerere – eftshift0 Apr 04 '19 at 14:43
  • When you've done more merges you'll have seen many textually-indistinguishable cases where the correct merge resolution isn't the one you want here, and you'll also have more skill using the merge resolution tools so doing the right thing, once you're sure what that is, will take about a second. – jthill Apr 04 '19 at 21:07

2 Answers2

3

Like the comments mentioned, Git is only so good at deciding how to put code together. You might be interested in merge strategy options though. You can run

git merge --strategy-option theirs or git merge --strategy-option ours

To favor either the source or the destination when it comes to conflicts. Read more about it here:

Resolve Git merge conflicts in favor of their changes during a pull

https://git-scm.com/docs/merge-strategies

Mike Faber
  • 481
  • 5
  • 17
2

I would advise against using -X ours or -X theirs (or their longer spelling equivalents, --strategy-option ours and the like) here.

The conflict that Git sees—remember, Git works line-by-line—is that in the merge base commit Git sees:

const a = 1;

In one of the two branch tip commits (let's call this the left hand side or ours one) Git sees:

const a = 1;
const b = 1;

This, to Git, looks like:

  • at the a=1 line (which matches) add const b = 1;

Meanwhile, in the other branch tip commit, theirs or the right hand side, Git sees:

const a = 2;

To Git, this looks like:

  • at the a=1 line delete a line, and insert const a = 2; instead

Both instructions "touch" the a=1 line, so Git declares a conflict.

If you tell Git to favor "ours" / the left hand side, Git will keep the add b = 1 line instruction, and throw away the delete a = 1 and insert replacement line instruction. If you tell Git to favor "theirs" / the right hand side, Git will keep the instruction that replaces a=1 with a=2, but will throw away the other instruction.

Either way, you'll end up with the wrong resolution. The right resolution is actually to accept both changes even though they appear to conflict. Git has no way to do that automatically.

What I like to do for this case is to set merge.conflictStyle to diff3. That way, when Git leaves the messy merge conflict result in my work-tree, the file reads:

<<<<<<< HEAD
const int a = 1;
const int b = 1;
||||||| merged common ancestor
const int a = 1;
=======
const int a = 2;
>>>>>>> master

With the default, the seven vertical bars and const int a = 1; base lines are missing (and sometimes the remaining lines are squished together even more). It's very hard to read. With the diff3 style, the base lines are there: you can see what everyone started with, and make your own decision whether to take both changes, just one change, or some third alternative that's better than either.

(See also http://psung.blogspot.com/2011/02/reducing-merge-headaches-git-meets.html)

torek
  • 448,244
  • 59
  • 642
  • 775
  • I wonder how to make git generate such ==== things like in your example when I do `git pull`. I already have `[pull] rebase = true [merge] conflictstyle = diff3` but it says it won't pull until I stash my changes. Then I stash and work on resolving if needed, but why can't it put things together for resolving when I do `git pull`? I want to start the process in 1 command, not 2. – Nakilon Dec 17 '20 at 23:39
  • @Nakilon: with `rebase = true`, `git pull` doesn't run `git merge` at all. Instead, it runs `git rebase` as its second command. (Remember that `pull` is just a convenience shortcut meaning *run `git fetch`, then run a second Git command to do something with what I just fetched*. The point of this is that `git fetch` just *gets* commits, but doesn't *do anything with them*, and after you get them, you eventually need to do something *with* them. Personally, I like the option of *looking at them* between the fetch step and the action, and `pull` prohibits this, so I avoid `pull`.) – torek Dec 18 '20 at 06:48
  • In any case, it's `git rebase` that requires the stash-or-otherwise-clean-up step. Rebasing itself consists of repeated cherry-picking, and *each* cherry-pick is a form of merge, but an unusual one. There is a way to make `git rebase` automatically run `git stash` for you, but I recommend *not* doing this. As I just noted, I also recommend avoiding `git pull` itself: use the individual commands yourself, so that you can see what you are doing (and can stop in between commands if and when that's useful to you). – torek Dec 18 '20 at 06:49