Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

What is the best way for distributed conflict resolution during merge in git? (deliberate partial commit)

Assume the following:

  1. A team of several designers (DesignerA,DesignerB,DesignerC ...).

  2. Main branch master

  3. Two feature branches featureA, featureB.

  4. In featureA:
    4.1. DesignerA Modified ./fileA.
    4.2. DesignerB Modified ./fileB.
    4.3. DesignerC Modified ./fileC.

  5. In featureB:
    5.1. DesignerA Modified ./fileA.
    5.2. DesignerB Modified ./fileB.
    5.3. DesignerC Modified ./fileC.

  6. DesignerC merges featureA + featureB into master:
    6.1. merge featureA to master:
    fileA,fileB and fileC's changes are automatically merged.

    6.2. merge featureB to master: fileC's conflict resolved by DesignerC fileA+fileB are conflicted but DesignerA owns fileA and DesignerB owns fileB.

My question:

How can DesignerC pass the partially merged commit and let each designer to solve his own conflicts?

say:

  • Send to designerA :
    • resolved fileC
    • unresolved fileA - to handle
    • unresolved fileB - to leave unresolved
  • Send to designerB :
    • resolved fileC
    • unresolved fileA - to leave unresolved
    • unresolved fileB - to handle
  • Merge resolutions and push to master.

NOTE:

  • The team tries to use git as simply as possible - please avoid fancy gitting in answers :)
  • The solution of temporary branches is not the one I am looking for.
question from:https://stackoverflow.com/questions/65916173/what-is-the-best-way-for-distributed-conflict-resolution-during-merge-in-git-d

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

1 Answer

0 votes
by (71.8m points)

There is no good way to do this

That doesn't mean you can't do it at all, but all ways that you can do it are currently rather bad. The fundamental problem is simple, and has three or more parts depending on how you count:

  • You can only push commits.
  • Conflict resolution takes place in Git's index.
  • New commits are made from Git's index.
  • You can't make a new commit until you resolve all the conflicts.

Users may use their working tree files, and/or additional files inserted into their working tree or anywhere else, to help out with the resolving, but fundamentally, a conflict exists because Git has modified its index such that some entry is marked "conflicted". To un-mark the entry—so that you can make a new commit, provided that this was the last conflict—you must resolve the conflict.

Hence, to make a commit that you can send to someone else so that they can resolve their part of the conflict, you must first resolve all parts of the conflict. Now you can commit and send the commit and they can ... uhhhmmmm ... undo your resolution of their parts of the conflict? Except, there's no conflict left.

Git could do this, if only you could commit a conflict

Unfortunately, you can't commit a conflict. But all the tools exist within the Git ecosystem. Conflicts exist because Git's index has non-zero-stage index entries. The user's working tree also has tracked and/or untracked files that may represent partial resolutions. If we could just take each of these—the non-zero-stage entries, and the tracked and untracked files—and make commits out of them and then use those commits to re-assemble the conflicted index and work-tree contents later, we'd have the makings of exactly what you want.

The git ls-files --stage output shows everything that is actually in Git's index. We just need to write a program that takes this output and creates multiple separate temporary indices (that, each, aren't conflicted but allow another program to build a new conflicted index later) and commits those, along with another commit or two to save the work-tree state. This mass of commits—however many are needed to save the stage 0, 1, 2, and 3 entries1 plus the work-tree state—would probably be best represented as a faked-up merge, a la git stash, and then indexed via some reference for temporarily resolved states that can be restored to resume merging later, a la refs/stash for git stash.

The similarities to git stash are clear enough, and the implementation would likely borrow from the old git stash shell script to some extent. The exact format for these commits, and the ref or refs to use, will require some thought and experimentation.

This command does not exist today.


1In theory, when there are conflicted entries at stage 1 in the index for instance, there could be more than one file with some specific name, such as path/to/file.ext. This would represent multiple merge bases. In practice Git doesn't seem to make use of this, and if it did, it is not clear how one would know which version of path/to/file.ext went with which merge base: would every file that has a stage-1 entry have to have N such entries, where N is the number of merge bases? What hash value would go in the index slot if, say, merge base #1 has no file named path/to/file.ext, but merge base #2 does?

This all affects the design of the in-progress-merge "merge commit" we would make for handling this.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...