BT643
BT643

Reputation: 3845

Find out which user is incorrectly resolving merge conflicts?

We're often getting issues with users "incorrectly" fixing git merge conflicts and breaking things.

Am I missing any git log parameters I can use to find recent merges which had conflicts, and which git user resolved said conflicts.

In some cases this is when someone merges master into the "test" branch, so it may contain many peoples work.

Workflow:-

The git workflow needs improving a lot and making stricter, but is there anything I can do for the short term to find the user incorrectly fixing the merge conflicts?

Upvotes: 1

Views: 104

Answers (1)

torek
torek

Reputation: 488213

In one way, it's really trivial. In another way, it's very hard.

Here is how it is trivial:

  • There is a merge. The merge is either done right, or it's done wrong. Look at the merge and see whether it was right or wrong. If wrong, the author and committer tell you who did that (to the extent that you trust author and committer1).

Here is how it is very hard:

  • There is a merge. Is it right?

There is no automatic way to find the answer to that question.

If you have good automated tests, you can get arbitrarily close to automatically answering the question. Good automated tests are not easy, and become very hard if you try to make them very good.

If you don't have automated tests, but do have some people who are good at doing merges correctly, you can perhaps do spot-checks: simply have these good folks repeat the merge themselves, and compare their result to the earlier result. If it is the same, the original merge was done correctly. If it is different, it was not.

The presence or absence of merge conflicts is not a sure indicator as to whether a merge was done correctly. Git has no secret knowledge: it merely combines text according to a fixed set of rules. That said, if you wish to pick out, for manual testing, specifically those merges that did see conflicts, you can automate this part. Just repeat the merge (making sure git rerere is not turned on) and see if there are conflicts.

Repeating a merge

Above, the phrase "repeat the merge" appears twice. You may wonder how you can repeat a merge. This is mostly trivial.2 First, find each merge's commit ID:

git rev-list --merges <start-point> [additional options if desired]

This produces a list of candidate IDs. (You will want to save them all somewhere, and annotate which ones you have checked so that you do not have to re-check them later. Use whatever ad hoc solution you like here.)

Then, given a merge ID, simply check out its first parent as a detached HEAD, and run git merge on its remaining parent IDs (this bit relies on POSIX shell behavior and syntax):

id=c79a113...          # or whatever, from your list
set -- $(git rev-parse ${id}^@)
git checkout $1        # check out first parent
shift                  # now that we have $1 out, discard $1
git merge $*           # (attempt to) merge the remaining commits

The rev^@ notation is from gitrevisions and means "all parents of the given revision". If all your merges are standard two-parent merges, you can use the clearer (but less general):

git checkout ${id}^1
git merge ${id}^2

(the gitrevisions syntax and shell set and shift technique allows for octopus merges).

Since this merge is being made on a detached HEAD, the resulting merge, if it completes automatically, can be trivially abandoned by checking out any other commit or branch-name. If the git merge fails with a conflict, you have a conflicted merge, with the usual results in the index; you can go on to finish the merge, or use git merge --abort to terminate it. (The exit status from git merge will be 0 if the merge succeeds and nonzero if not.)


1Remember that, except for commit transfers through push or fetch, every Git operation is done locally by someone in complete control of his or her own repository. The user can of course lie and claim to be someone else. If you control this at all, you can and must do so at the transfer boundary: when you pick up a commit from someone else—whether by git fetch from your end, or git push from their end—you know who you are talking to (through whatever authentication you have put in place: this is entirely outside Git, and is usually from ssh or https these days, often wrapped up in third party extensions like Gitolite, or provided as a service by something like GitHub). You have the chance, at this time, to do whatever verification you like, before accepting the commits.

Alternatively, you can check "after the fact" using, e.g., PGP signatures. If someone has PGP-signed some tags and/or some commits, and you can verify these signatures, you can choose to believe that those tags and/or commits are theirs. You can then extend that trust (to whatever extent you are willing, of course, based on the security of SHA-1 and how much you trust the signer) to those commits' and/or tags' ancestors, since building an object that matches a predefined SHA-1 and its text is at least very hard. (This is called second pre-image resistance; see, e.g., this crypto.stackexchange.com question.)

2I say "mostly trivial" because options the user supplied to git merge are not available here. You could require users who use non-standard merge options to record them in their commits, or in notes attached to the commits, but this is difficult to enforce. See also footnote 1: you can only apply enforcement rules at the transfer boundary.

Upvotes: 2

Related Questions