Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collaborating on fixing merge conflicts

Tags:

git

Scenario: Have a branch per (active) release in git,

Sequence is:

  1. Bob makes changes to R1 , commits, pulls R1 and pushes R1 to shared. Does not update R2 on shared.
  2. Jane makes changes to R1 , commits.
  3. Jane pulls R1 from shared, deals with any conflicts, pushes R1.
  4. Go to Step 1 again for a few times
  5. Jane gets told they need to bring R2 up-to-date with fixes from R1
  6. Jane pulls R1 and R2 from shared
  7. Jane merges R1 into R2 locally. Merge conflicts in some area of code Bob's worked on.

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.

Branches: R1, R2

 State of Shared Repository

 C1    - Bob
 |
 C2-+  - Jane
 |  |
 |  C3 - George
 |  |
 |  C4
 C5 |  - Bob
 |  |
 C6 |  - Jane  [R1]
    |
    C7 - Alice [R2]

Bob and Jane make changes to R1

Jane then wants to merge R1 into R2 to update the latest release. She solves the merge conflicts caused by her changes, however she doesn't know how to solve the conflicts cause by the changes Bob made.

Is there a way for Jane to use git and have Bob complete the merge?

I know ideally, Bob would have already merged his changes into R2, but suppose that isn't the case.

Possible workarounds (looking for something better)

  1. Jane calls Bob over to her desk and Bob then resolves the conflict. Difficult when telecommuting
  2. Jane saves conflicted file(s) and email to Bob, Bob fixes file and emails them back to Jane who then uses them in her commit.
like image 208
Joseph Kingry Avatar asked Jul 18 '13 18:07

Joseph Kingry


3 Answers

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.

like image 186
Greg Bacon Avatar answered Sep 17 '22 18:09

Greg Bacon


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.

like image 28
Schleis Avatar answered Sep 17 '22 18:09

Schleis


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).

like image 35
jeffi Avatar answered Sep 18 '22 18:09

jeffi