0

I have a bunch of files that I have deleted in develop, and those files have been modified in master. I want to merge master into develop, but I am getting a merge conflict, since both branches have modified the same file.

How do I merge master into develop, and accept all changes present in develop? I tried git merge -s recursive -X ours master, per this quesiton, but I still got a bunch of conflicts. I tried git merge -s ours master, but I got an empty commit.

ewok
  • 20,148
  • 51
  • 149
  • 254
  • To clarify: you want `master` and `develop` to end up the same, with all `master` changes dropped and all `develop` changes accepted? – Paul Hicks Aug 23 '17 at 20:56
  • @PaulHicks no. I want `master` to retain all of its changes, and `develop` to merge in all files from `master` that do not conflict with changes in `develop`, and discard changes from `master` that do. – ewok Aug 23 '17 at 20:58
  • there were conflicts between `master` and `develop`, yes. there were about 10 files that had been modified by `master` and not touched by `develop`, but there were 18 files that were modified in `master` and deleted in `develop`. I had a clean working directory with no local changes – ewok Aug 23 '17 at 21:14
  • Ah.. a delete will conflict with a change, even with `-X ours`. You will have to merge those manually. It's as simple as `git rm`ing the files, then re-running the merge command to accept the deletions. – Paul Hicks Aug 23 '17 at 21:16
  • 1
    Don't follow. They were already `git rm`ed. And those deletions had already been committed to `develop`. – ewok Aug 23 '17 at 21:17
  • Actually, since they're already `git rm`ed in develop, you want to simply `rm` them during the merge. – Paul Hicks Aug 23 '17 at 21:17
  • Possible duplicate of [Git merge strategy 'theirs' is not resolving modify/delete conflict](https://stackoverflow.com/questions/25254037/git-merge-strategy-theirs-is-not-resolving-modify-delete-conflict) – max630 Aug 24 '17 at 03:05

2 Answers2

2

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 added (or git rmed if appropriate), running git commit will finish the merge. This commit takes whatever is in the index at this point.

torek
  • 448,244
  • 59
  • 642
  • 775
  • so it isn't possible to tell git that, for all conflicts, I want our changes? – ewok Sep 05 '17 at 16:32
  • Only for "low level" (within-file) conflicts. One might think `-X` arguments should apply to high level conflicts too, and perhaps they *should*, but the code happens to be written to just pass `-X whatever` on to the low level merge program. If there is a high level conflict, the low level program never runs in the first place! – torek Sep 05 '17 at 16:38
  • is there some way to implement this ability? a custom merge strategy or something? or am I just SOL? – ewok Sep 05 '17 at 16:39
  • 1
    If you write your own merge *strategy*, yes: you take over the entire job of merging. You find the merge base(s); you compute any diffs you care to find; you compute the result; and you make the final commit. Just place a program named `git-merge-foo` in your `$PATH` and run `git merge -s foo`; your program will be invoked, and can (and must!) do the whole job at that point. – torek Sep 05 '17 at 16:59
0

Use a merge tool. Here is one example:

git mergetool --tool emerge

commands:

a- choose change in A

b- choose change in B

n- next change

p- previous change

q- finish merge

info on emerge

In the future I would only merge into master. have a Master and Develop branch, then branch off of develop, when you want to update master, merge develop into master. Then continue on in that fashion.

Timmy
  • 1
  • 2