Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get git to resolve merge conflicts by putting "ours first, then theirs"

Tags:

git

git-merge

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 [email protected]:abznak/merge_conflict_example.git

like image 880
Tim Smith Avatar asked Nov 26 '25 13:11

Tim Smith


2 Answers

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) }
like image 106
torek Avatar answered Nov 28 '25 15:11

torek


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
like image 27
Tim Smith Avatar answered Nov 28 '25 15:11

Tim Smith



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!