3

For instance, master branch has init commit with content created by:

echo "init" > data

I created feature branch:

git checkout -b feature

Then was serially committed changes:

for newLine in feature1 feature2; do echo "$newLine" >> data; git commit -am "$newLine" ; done

I want to change feature1 commit:

git rebase -i master

Make 'edit' feature1 commit, change data file and continue rebase:

sed -i 's/feature1/F/g' data; git add data; git rebase --continue

But there is conflict:

init
<<<<<<< HEAD
F
=======
feature1
feature2
>>>>>>> f4ac9dc... feature2

Is it possible to avoid this conflict. I just need to apply diff. Result would be:

init
F
feature2

Not suitable solutions:

git rebase -s recursive -X {ours,theirs} -i master
David Neiss
  • 8,161
  • 2
  • 20
  • 21
Jaz Brok
  • 231
  • 1
  • 4
  • 18

2 Answers2

2

No; at least, it's not (easily) possible to avoid or ignore this conflict. The edits are just too close together.

(What follows is a description of git's default behavior. Leon's answer shows one way to work around these limitations by defining a custom mergetool.)

Merging works by creating a patch (as with diff -u) representing the changes in one branch, and applying it (as with patch) to the other branch. In order to apply a patch, the context has to be the same. (See How do diff/patch work and how safe are they?) The context, i.e. the few lines surrounding the actual deletions and insertions in the diff, is what tells the patch tool that it is patching the right part of the file.

Git will not delete a line that doesn't exactly match the line that was deleted in the original, and it won't insert a line except between lines that exactly match the original. So it won't insert 'feature2' after 'F' because it says in the patch that 'feature2' comes after 'feature1' (and not after 'F').

When merging, you will have to resolve this conflict every time a change occurs in the vicinity of the conflict. This can get tedious when you apparently have to make the same correction for a few dozen commits in a row, but I don't know of a good way around it.

In certain circumstances, you may be able to use a different merge strategy to make your life easier. Be careful with this feature because some strategies are less conservative than the default and may be happy to break your code. Regardless, I don't think there is a merge strategy that will solve the example problem.

Community
  • 1
  • 1
trent
  • 25,033
  • 7
  • 51
  • 90
  • 1
    +1 as I wanted to write the same answer, but then changed my mind in favor of finding a way of automatically performing conflict resolution for the described case (e.g. using a custom script). Hoping to post an answer that will prove the '"No, it's **not possible**" part of your answer wrong :) – Leon Jul 11 '16 at 17:08
  • You *can* use `git rerere` to tell Git to "re"use the "re"coreded "re"solution. These are recorded at "git add" time (if rerere is on) and (of course) save the conflict-and-resolution pair, and then (if rerere is on) when you get a conflict, Git looks for a recorded resolution and re-uses it. – torek Jul 11 '16 at 20:36
  • I seem to have come up with a simple mergetool that resolves such conflicts automatically. See [my answer](http://stackoverflow.com/a/38316531/6394138). – Leon Jul 11 '16 at 21:50
2

I was able to come-up with a custom mergetool that allows to automatically resolve conflicts for the described scenario under the following assumptions:

  1. The amending change and upstream changes (if any) are limited to changed lines (i.e. no lines are added or removed).

  2. The conflict is solely due to abutment of changes (i.e. the changes must not overlap).

Then, such a conflict can be resolved by converting the later change to an ed script, that is expressed via absolute line numbers, and running that script on the local version of the file.

The dummymerge script below implements that idea.

It must be registered with git as follows:

git config mergetool.dummymerge.cmd 'dummymerge $BASE $LOCAL $REMOTE > $MERGED'
git config mergetool.dummymerge.trustExitCode true

Use it to auto-resolve conflicts of the described type as follows:

git mergetool -t dummymerge

dummymerge

#!/bin/bash

myname=$(basename "$0")

if [ $# -ne 3 ]
then
    echo "Usage: $myname base_rev rev1 rev2"
    exit 1
fi

diff -e "$1" "$3"|patch -e -o - "$2"
Leon
  • 31,443
  • 4
  • 72
  • 97
  • It does exactly what i want. Is it possible to invoke 'git mergetool -t dummymerge' when merge conflict while rebase automatically? – Jaz Brok Jul 12 '16 at 11:51
  • @JazBrok A superficial search didn't find an easy way of doing that. At this point I would not immediately try to invoke the script automatically, since it is not foolproof (doesn't check if the stated assumptions hold) and may clobber your files. I recommend using it manually for a while and validating its results. If it proves to work without problems, then you can post a new question about invoking a custom merge tool automatically. – Leon Jul 12 '16 at 12:07