Just as some quick background, when you run git merge otherbranch
:
Git examines the commit graph, which generally looks like this only more complicated:
...--o--B--o--o--L <-- yourbranch
\
o--o--o--R <-- otherbranch
I have labeled three specific commits here, B which is the merge base, L which is the left-side or local or --ours
commit, and R which is the right-side or remote or --theirs
commit.
Git then runs two git diff
commands, more or less, as with:
git diff --find-renames B L > /tmp/diff.B-to-L
git diff --find-renames B R > /tmp/diff.B-to-R
The merge process itself then consists of picking up one copy of each of the changes in these two diffs. For a file that's modified only in B-to-L or only in B-to-R, that's really easy: Git can just take the L or R version of that file. For a file that's not modified at all, Git can take the B, L, or R version of the file, as there's no difference between any of them. It's only files that have been changed somehow in both L and R, with respect to B, that require hard work (a "low level" merge).
The biggest problem, though, comes about when you have a situation like yours: the file is modified on one side, but removed entirely on the other side. It's not clear to Git whether to resolve this by taking the individual line changes, or removing the file entirely. (You get the same kind of conflict if a file is renamed in both B-to-L and B-to-R, but to two different names; or if a new file is added in both B-to-L and B-to-R, but with the same name.)
I call these high level conflicts, and Git will not resolve them, not even with -Xours
or -Xtheirs
. For conflicts within a single file—which I call low level conflicts, where some file.ext
has changes on both sides that overlap—Git will normally stop with a conflict, but with the eXtended options -Xours
or -Xtheirs
, Git will favor the "ours" or "theirs" change for that particular conflict.
With high level conflicts, however, you must resolve them yourself. If the correct resolution is to remove the file, run git rm <filename>
. If the correct resolution is to keep the modified file, run git add <filename>
. If the correct resolution is something else, do the something else, then git add
the resulting file(s). Note that these git add
and/or git rm
operations work on the index, copying files from the current work-tree. Conflicted files are represented by extra index entries; these extra entries are cleaned up and put away when you git add
or git rm
.
Once all high and low level conflicts are resolved and all the resolutions have been git add
ed (or git rm
ed if appropriate), running git commit
will finish the merge. This commit takes whatever is in the index at this point.