3

I'm using Flyway to keep track of database changes, and git for version control.

Flyway depends on migration scripts, which are named with increasing numbers for each migration.

Now I have the following situation: two features were developed on two separate branches (let's call them A and B), both requiring database changes. Both developers created a migration script for the database for their branch. As they branched off master at around the same time, they both assigned the same filename to the migration script: V42__migration.sql.

Now branch A was merged into master. When merging branch B, I got into a merge conflict because of the V42__migration.sql file. The correct solution to solve this conflict would be to rename the migration script of the branch B to V43__migration.sql. However, at time of merging git tries to merge both files in to one, where I actually need both of them untouched, but one renamed.

What's the best way to solve this kind of merge conflicts with git?

Bob
  • 5,510
  • 9
  • 48
  • 80

3 Answers3

6

Once git reports the conflict, you are at a prompt and fully able to edit the index in any way you require, to resolve the conflict. So if you're merging feature_x in, you could:

1) Get the branch's script and name it V43

git checkout feature_X -- V42__migration.sql
mv V42__migration.sql V43__migration.sql

2) Get the V42 script from the previously merged commit

git checkout HEAD -- V42__migration.sql

3) Make sure the index is updated properly and finish the merge

git add .
git commit

Another thing to consider, going forward, is that you don't really want git attempting to merge these files. So you could use .gitattributes to either mark the files as binary, or apply a custom merge type to them. I would assume a pattern like whatever/path/to/V*__migration.sql would identify the files.

The idea is that if git thinks it has to merge such a path, it should automatically flag a conflict and it should pick one or the other version to keep as the tentative resolution. The person resolving the conflict then just has to put the other version in place.

Logically it makes sense to keep "ours" during the merge, because that's the version that will ultimately get that filename. This is what would happen if you mark the path as binary.

But pragmatically resolution is simpler if you keep "theirs".

mv conflicted_file next_filename
git checkout HEAD -- conflicted_file

So you might want to look up how to create a custom merge driver in the gitattributes documentation. (It's not as hard as it sounds; the driver can be something like cp %B %A && false. So just a couple of config commands.)

Mark Adelsberger
  • 42,148
  • 4
  • 35
  • 52
0

You have branches A and B, both containing a file with the same name, that does not exist in master. Merging A into master works fine, when you merge B, you get a merge conflict.

$ git checkout master
$ git merge A             # OK
$ git merge B             # CONFLICT (add/add): Merge conflict in file

Such a merge conflict looks as follows.

<<<<<<< HEAD
AAA
=======
BBB
>>>>>>> B

Now instead of merging these files, you can split these files again and rename the file from branch B to V43__migrate.sql. For removing lines between a pattern, sed can be used as follows.

$ sed '/<<<<<<< HEAD/,/======/d' V42__migration.sql | sed '/>>>>>>> B/d' > V43__migration.sql
$ sed '/======/,/>>>>>>> B/d' V42__migration.sql | sed '/<<<<<<< HEAD/d' > V42__migration.sql

Then you can commit those changes.

$ git add V42__migration.sql V43__migration.sql
$ git commit

*NIX Tricks: [sed] Delete the lines lying in between two patterns

conspicillatus
  • 195
  • 3
  • 11
  • 2
    I recommend against using sed or other techniques to "un-merge" the file. Git will happily check out the originals upon request, and then there's no risk of mucking it up. – Mark Adelsberger Jul 05 '17 at 13:45
-1

If you don't rely on splited commits on the unmerged branch, squash all commits on the brach to one single commit. You have to force the push to your branch git push -f (the old commits are overwritten and replaced by your new one).

Rename the file in the unmerged branch and ammend git commit --ammend your changes. Ammending also needs a forced push .

This may be more tricky if you didn't squash the commits.

Zian
  • 559
  • 4
  • 16
  • `squash`ing the commits adds nothing but to throw away history. `amend`ing the branch head will work, but fixing the problem during the merge makes a lot more sense. – Mark Adelsberger Jul 05 '17 at 13:47
  • i avoid the conflict in the file at all. if you do not need the history on your branch (for example because you want to have a single commit for a completed feature), its absolutely valid. – Zian Jul 05 '17 at 14:13
  • No, telling someone that to fix one problem they need to create another (that you assume doesn't matter) is not valid. The squash would be unnecessary *even if* amending were the correct solution. – Mark Adelsberger Jul 05 '17 at 14:16
  • And as to why `amend` isn't the correct solution: the purpose of the rename is to resolve the merge. If different things were merged (which, by the way, could happen while you're continuing to adjust things off in a branch), then the rename would be different. Resolving merge conflicts in the merge, rather than trying to anticipate and "avoid" them, is the better solution. – Mark Adelsberger Jul 05 '17 at 14:20
  • i prefer clean merges without manual changes as these changes can not be reviewed by a third person without much effort (as he has cannot see in one diff, what changed so easily). – Zian Jul 05 '17 at 14:27
  • manual merges don't preserve a useful history. this can lead to a lot of clutter – Zian Jul 05 '17 at 14:35
  • 1
    Argue all you want; you won't convince me that merge conflict resolution should occur anywhere other than in the merge. The history is perfectly usable; the "extra effort" is the `-m` flag. And none of this would justify your spurious statement that OP should squash commits - which wouldn't be needed even if `amend` were the correct solution. (Speaking of things that don't usefully preserve history...) – Mark Adelsberger Jul 05 '17 at 14:37