Search code examples
gitgit-branchconflictgit-rebasemerge-conflict-resolution

Resolving conflicts in a team with a big project


I'm interested in learning the best way to resolve conflicts in a big team.

For example I have a master branch in which the team has made quite a lot of changes and then I'm rebasing latest changes from the upstream (master and upstream are not connected). And I got conflicts. The problem is that somebody in the team knows better how to solve conflicts in one file and some other knows better about the other.

So the question is: is it possible to push unresolved branch to remote wait until colleagues resolve conflicts in their local environments and push them back and then make git rebase --continue.

And if not what is the best way to solve this problem?


Solution

  • The short answer is no, you cannot push a conflicted merge.

    The slightly longer answer is that merging takes place in (and via) git's index (also called the staging area). The index has a dual role, of acting as a staging area for the next commit, and also as a cache to speed up scanning the work tree. For merge purposes the cache aspect can mostly be ignored.

    In the index, every entry that corresponds to a work-tree file has up to four "slots" (at most three of which are in use), called stages:

    • Stage 0 is a normal, unconflicted file.
    • Stage 1 is the common ancestor version of a conflicted file;
    • Stage 2 is the "target branch" version (basically the version from the branch you're on as you do the merge); and
    • Stage 3 is the "merge branch" version (from the branch you're trying to merge).

    If a file has no conflicts, stages 1-3 are empty; if a file has a merge conflict, stage 0 is empty, and some or all of slots 1-3 are populated (depending on the particular merge conflict, some may be empty, e.g., perhaps the conflict is "both created" in which case there's no common ancestor, or perhaps it is "modified by them but removed by us" in which case there's no stage-2 entry).

    To mark a file as resolved, you git add or git rm its path; this removes the stage 1-3 entries and puts in a stage 0 entry (for git rm the stage 0 entry is "this file is to be gone once we make a commit").

    When making a new commit, git transforms the staging area into a set of "tree" objects that will describe all the files that go in that commit. To make trees from the staging area, it can only have stage-0 entries; only those entries go into the tree.

    When you use git push or git fetch, you transfer commits between repositories. Only whole commits (and their trees and other related objects) are transferable this way. Hence a conflicted, in-process merge, which happens in the index and uses stages 1-3, cannot be transported across machines. This is a fundamental design limitation of git as it is implemented today.