Collaborating on fixing merge conflicts

Assuming Bob is blocked and Jane is anxious to move the issue along, Jane makes her best attempt at performing the merge.

$ git fetch
$ git checkout R2
$ git merge --ff-only origin/R2
$ git checkout -b wip/R2-with-R1

Above wip stands for work in progress and is a convention that signals to the team that the tree and history are subject to radical change. Perhaps Jane really wants Bob to look over her resolutions that impact his code from R1 before integrating them into the baseline. (Note: this is an anti-pattern; a better approach would be to have automated tests that protect the desired behavior for the new code in R1 and allow developers other than Bob to merge confidently.)

Jane makes her best attempt at the merge.

$ git merge origin/R1
$ hack
$ git add ..
$ hack
$ git add ..

The wip/R2-with-R1 branch may even contain multiple checkpoint-style commits. Another good signal for each to contain would let the team know that it is speculative.

$ git commit -m 'FIXME: fix conflicts in Potrzebie'

When she is ready for Bob to look at it, she pushes it to a repository they can both see

$ git push --set-upstream origin wip/R2-with-R1

The --set-upstream option is there in case they need to work collaboratively on the new branch.

She then fires up her mail user agent.

To: Bob
From: Jane
Subject: speculative merge: wip/R2-with-R1

Bob: please look over my attempted merge in the subject branch and make
any necessary fixes that I may have overlooked.

I am particularly concerned about my Potrzebie conflict-resolutions.
Changes there always seem to bite us one way or the other.

Thanks,
Jane

After Bob’s fix and a fetch, the history will resemble

$ git lola
* 77d472c (origin/wip/R2-with-R1) fix by Bob
* ba1eb24 (HEAD, wip/R2-with-R1) FIXME: merge 2
*   80c207d FIXME: merge 1
|\
| * 2cf6ad4 (origin/R1, R1) R1 #2
* | 137b39d (origin/R2, R2) R2 #2
* | cb9a761 R2
...

At this point, Jane wants to preserve the merge but does not want to keep the ugly checkpoint commits. Squashing back to a merge commit requires just a bit of care.

$ echo Merge R1 into R2 | \
  git commit-tree origin/wip/R2-with-R1^{tree} \
  -p $(git rev-parse origin/R1) -p $(git rev-parse origin/R2)
84b177c498bc635612b66932f3d41096999e6d3f

$ git checkout R2
Switched to branch 'R2'

$ git merge --ff-only 84b177c498bc635612b66932f3d41096999e6d3f
Updating 137b39d..84b177c
Fast-forward
...

This leaves a history of

$ git lola
*   84b177c (HEAD, R2) Merge R1 into R2
|\
| | * 77d472c (origin/wip/R2-with-R1) fix by Bob
| | * ba1eb24 FIXME: merge 2
| | *   80c207d (wip/R2-with-R1) FIXME: merge 1
| | |\
| |/ /
| | /
| |/
|/|
* | 2cf6ad4 (origin/R1, R1) R1 #2
| * 137b39d (origin/R2) R2 #2
| * cb9a761 R2
...

and R2 now has by construction the same tree as Bob’s final tree.


If I'm understanding the sequence of action correctly, it's as follows:

  1. Bob makes changes to R1, commits, merges with his copy of R2 and pushes to shared.
  2. Jane makes changes to R1, commits, merges with her copy of R2 and attempts to push to shared, but gets an out-of-date error.
  3. Jane must fetch R2 from shared and handle the merge before she can push. But, she doesn't know what to do with Bob's changes.

In this situation, Jane and Bob could do the following:

  1. Jane can create a branch on shared containing her changes to R2:

    git push origin R2:R2-from-Jane
    
  2. Jane can then call/email/IM Bob and ask him to merge in his changes.
  3. Bob sighs discontentedly at having to do this again, then resolves the merge with Jane's branch from the server:

    git fetch origin R2-from-Jane
    git checkout R2
    git merge R2-from-Jane
    git push
    git branch -d R2-from-Jane
    
  4. Bob replies to Jane to let her know the merge is finished.
  5. Jane removes her temporary branch from the server:

    git push origin :R2-from-Jane
    

    and then replies back to thank Bob.

(Obviously, Bob could also handle deleting Jane's temporary branch on the server, but that didn't fit with the narrative as well.)


Other than Jane calls Bob over to her desk and reviews the changes at her computer, I don't think that this can be done in git.

When the merge is being resolved, you are creating a new commit and that is all happening locally. Jane could make the merge and decide not to push the changes to the remote. Until the merge commit has been pushed there is no way to know whether someone else merged into their copy of the remote. Jane has to resolve the commits in order to complete the merge and that is only happening locally.

Having un-merged changes in the remote seems to be a bad idea anyway. Supposing that I start working with the repo and pull changes before Bob finished resolving the conflicts. What then?

The other way for Jane to know if she resolved the commits would be that she has a test suite to run. Then she knows she made a mistake when tests start failing.


We are in a similar situation.

Here's the way which we have found somehow work after a few different failed aproaches. The point was how to share the conflicted hunks over remote repository.

  1. Jane creates two branches from the tip of R2 and merge R1 onto them with a set of 'complementary' merge strategies;

    $ git branch wip/reference R2
    $ git checkout wip/reference
    $ git merge -s recursive -X theirs R1
    
    $ git branch wip/merging R2
    $ git checkout wip/merging
    $ git merge -s recursive -X ours R1
    
  2. Now

    $ git diff wip/reference..wip/merging
    

    shows how R1 would have conflicted with R2 because '-s recursive -X ours/theirs' merge strategy "forces conflicting hunks to be auto-resolved cleanly by favoring our/their version."

  3. Jane makes necessary changes on wip/merging so to solve the 'virtual' conflicts caused by her previous changes and leaves Bob's untouched.

  4. Then Jane pushes wip/reference and wip/merging and call/IM/email/owlpost Bob to fetch them.

  5. Bob checks the virtual conflicts and the halfway resolution Jane made and makes further changes against the conflicts his past change caused.

  6. Then he merges wip/merging back to R2 if he feels everything looks good or optionally ask George/Alice to make further resolutions.

We are still under investigation how this affects later merges (i.e. if git rerere properly works).

Tags:

Git