Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
221 views
in Technique[技术] by (71.8m points)

How do you detect an evil merge in git?

I've created a simple git repo to illustrate my question, available on GitHub here: https://github.com/smileyborg/EvilMerge

Here's an illustration of the repo history:

master          A---B---D---E-----G-----I
                      /              /
another_branch    ----C              /
                                    /
another_branch2                 F---H

(In the actual repo on GitHub, D is 4a48c9, and I is 48349d.)

D is a "simple" evil merge, where the merge commit "correctly" resolves a merge conflict, but also makes an unrelated "evil" change that did not exist in either parent. It is possible to discover the "evil" part of this merge by using git show -c on this commit, as the output includes ++ and -- (as opposed to single + and -) to indicate the changes that did not exist in either parent (see this answer for context).

I is a different kind of evil merge, where the merge commit "correctly" resolves a merge conflict (caused by changes from F to file.txt that conflict with changes from G), but also "evilly" discards the changes made to a completely different file file2.txt (effectively undoing the changes from H).

How can you know that I is an evil merge? In other words, what command(s) can you use to discover that I not only manually resolves a conflict, but also fails to merge changes that it should have?

Edit/Update: What is an evil merge?

As pointed out by René Link below, it is hard (perhaps impossible) to define a generic set of criteria to identify an "evil merge". However, much like Supreme Court Justice Stewart said about pornography, evil merges are something you know when you see.

So perhaps a better question to ask is this: what git command(s) can you use on a merge commit to get a diff output of all novel changes introduced solely in the merge commit itself. This diff should include:

  • all merge conflict resolutions (at least, if the resolution involved anything more complex than choosing one parent's changes over the other's)
  • all additions or removals that did not exist in either parent (as seen in D)
  • all changes that did exist in one of the parents but that the merge commit discards (as seen in I)

The goal here is to be able to have a human look at this output and know whether the merge was successful or (accidentally or maliciously) "evil" without having to re-review all the previously-reviewed changes (e.g. F and H) that are being integrated in the merge.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The easiest thing to do would be to diff the results of your conflict resolution with a merge that auto-resolves conflicts without human intervention. Any automatic resolutions will be ignored, since they will be resolved in exactly the same way.

I see two ways of visualizing the possible "evil" resolutions. If you are making this into a script add &> /dev/null to the end of all lines that you do not care to see output.

1) Use two separate diffs, one that favors the first parent, and a second that favors the second parent.

MERGE_COMMIT=<Merge Commit>
git checkout $MERGE_COMMIT~
git merge --no-ff --no-edit -s recursive -Xours $MERGE_COMMIT^2
echo "Favor ours"
git diff HEAD..$MERGE_COMMIT
git checkout $MERGE_COMMIT~
git merge --no-ff --no-edit -s recursive -Xtheirs $MERGE_COMMIT^2
echo "Favor theirs"
git diff HEAD..$MERGE_COMMIT

2) Diff against the results of the conflicted merge with the conflicts still in.

MERGE_COMMIT=<Merge Commit>
git checkout $MERGE_COMMIT~
git -c merge.conflictstyle=diff3 merge --no-ff $MERGE_COMMIT^2 --no-commit
git add $(git status -s | cut -c 3-)
git commit --no-edit
git diff HEAD..$MERGE_COMMIT

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...