3

I would like to be able to automatically resolve "two branches added blocks at the same line" conflicts by putting the "ours" block first, then the "theirs" block.

So instead of a conflict like:

16:09:44 tims@firebat ~/git/merge_conflict_example (master|MERGING) $ cat test.txt
good morning
good evening
<<<<<<< HEAD
g'day
=======
aloha
>>>>>>> branch1
hello
hi

I'd just get:

16:09:44 tims@firebat ~/git/merge_conflict_example (master) $ cat test.txt
good morning
good evening
g'day
aloha
hello
hi

with no conflict.

I figure there might be something like git merge branch1 -X oursthentheirs

The sample I used here is available at git@bitbucket.org:abznak/merge_conflict_example.git

Tim Smith
  • 1,714
  • 2
  • 12
  • 14

3 Answers3

2

There's nothing built in, but if you set merge.conflictstyle to diff3, it would be relatively easy to write a program (in perl or python perhaps, or I'll write a cheesy version in awk) that checks whether the "original" section is empty—this will detect the "both added" situation—and if so, simply removes the conflict markers:

good morning
good evening
<<<<<<< HEAD
g'day
|||||||
=======
aloha
>>>>>>> branch1
hello
hi

Here's my awk script (which I don't claim to be good, but it works on the sample input). Note that it won't handle "nested conflicts" very well (i.e., if the two original conflicting files contain what look like conflict markers, this will go wrong).

BEGIN { in_conflict = retained_left = retained_mid = retained_right = 0 }
function handle_retained(is_eof) {
        # If the section between ||||||| and ======= is empty,
        # retained_mid+1 == retained_right.  Otherwise print
        # all the retained conflict lines.
        if (retained_mid + 1 == retained_right) {
                s1 = retained_left + 1  # after <<<<<<<
                e1 = retained_mid - 1   # before |||||||
                s2 = retained_right + 1 # after =======
                e2 = NR - 1             # before >>>>>>>
        } else {
                s1 = retained_left; e1 = NR
                s2 = 1; e2 = 0
        }
        for (i = s1; i <= e1; i++)
                print retained[i]
        for (i = s2; i <= e2; i++)
                print retained[i]
        delete retained
        if (is_eof) {
                # this should never happen!
                print "WARNING: ended input while still in conflict marker"
                exit(1)
        }
}
/^<<<<<<</ { in_conflict = 1; retained_left = NR }
{
        if (!in_conflict)
                print
        else
                retained[NR] = $0
}
/^\|\|\|\|\|\|\|/ { if (in_conflict) retained_mid = NR }
/^=======/ { if (in_conflict) retained_right = NR }
/^>>>>>>>/ { if (in_conflict) handle_retained(0); in_conflict = 0 }
END { if (in_conflict) handle_retained(1) }
torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    Well, awk certainly looks like it’s a lot of fun. +1 for that mess… :D (and effort) – poke Nov 09 '15 at 08:01
  • I should add a few notes, for anyone not familiar with awk: `NR` is the "record" (line) number of the current input line, starting at 1 and counting up for all input lines. Lines of the form `/pattern/ { action }` execute the given action, and a missing `/pattern/` always executes; these execute in order, so we check for 7 `<`s first, then do the print-or-retain, then check for 7-`|` etc., on every line. – torek Nov 09 '15 at 08:13
1

It's easy. Just set the merge gitattribute to union. From https://git-scm.com/docs/gitattributes:

union

Run 3-way file level merge for text files, but take lines from both versions, instead of leaving conflict markers. This tends to leave the added lines in the resulting file in random order and the user should verify the result. Do not use this if you do not understand the implications.

For the example, I just added a .gitattributes file containing the text *.txt merge=union:

10:58:21 tims@thor ~/git/merge_conflict_example (master) $ cat .gitattributes
*.txt merge=union

And ran the merge:

10:58:26 tims@thor ~/git/merge_conflict_example (master) $ git merge origin/branch1
Auto-merging test.txt
[...]
Merge made by the 'recursive' strategy.
 test.txt | 1 +
 1 file changed, 1 insertion(+)

Which had the desired effect:

10:58:42 tims@thor ~/git/merge_conflict_example (master) $  cat test.txt 
good morning
good evening
g'day
aloha
hello
hi
Tim Smith
  • 1,714
  • 2
  • 12
  • 14
  • I was looking for a way of getting git to run @torek's solution automatically when I came across the answer. – Tim Smith Nov 12 '15 at 01:12
0

You can merge, say branch old into the current branch, using "ours" merge strategy like below

$ git merge -s ours old

Mayur Nagekar
  • 813
  • 5
  • 13
  • 1
    Merging with the `ours` strategy completely discards the other tree's changes, which is not what the OP wants. Merging with the `ours` modifier to the `recursive` strategy (`-X ours`) also discards the other tree's changes, but only in the case of conflicts. This retains some of the other tree's changes, but not any additions that are in conflict—so again it's not what the OP asked for. – torek Nov 09 '15 at 08:16