Reputation: 5628
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?
Upvotes: 4
Views: 3800
Reputation: 599
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.
Upvotes: -1
Reputation: 335
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
Upvotes: 0
Reputation: 45819
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.)
Upvotes: 7