Bob
Bob

Reputation: 5628

Resolve git merge conflict by renaming one of the files

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

Answers (3)

Zian
Zian

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

conspicillatus
conspicillatus

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

Mark Adelsberger
Mark Adelsberger

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

Related Questions