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.