Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git Merge vs Rebase - Resolving conflicts

This is a bit long, but I think it may be an interesting problem.

We just recently started to use git in our company despite a lot of people reluctance a few managed to start using it in small projects and now we're actually using it more relevant projects.

I always try to do a rebase before merging but just recently we found a problem with this approach.

Imagine you have a file F and you have the following git history:

(master)       F -- F''1
                \
(feature)        \- F'1 -- ... -- F'X

Now, if you do a rebase of the feature branch and, upon resolving the first conflict, you actually keep changes from F''1 and F'1 you'll will have to manually resolve X conflicts for the file F because git can't auto resolve them. As opposed, if you just did a merge (without rebasing) you would have to solve just one ("big") conflict. This made me question the actual value of rebasing because this can be a really tedious work.

Am I missing something or is this just the way it is? If you have 30 commits over one file you'll have to go through each and every commit and resolve any conflict manually. Is there a more appropriate way to deal with this situation?

I'm sorry if I didn't explain very well but you can try to replicate the steps I've mentioned in a dummy repository and I think you'll get what's bugging me.

like image 479
prototyp3PT Avatar asked Apr 18 '16 10:04

prototyp3PT


1 Answers

You are correct: you must keep re-resolving conflicts, usually the same way.

There is, however, an automation knob for doing this, called git rerere. The three re-s stand for reuse recorded resolution.

The way this works is that every time you hit a conflict, and when you git add the resolved version, git saves both the original conflict (minus the line numbers) and the resolution in some files (actually just blob objects inside the repository). Then, before announcing a conflict, the merge code checks to see if the original conflict is already associated with a resolution. If so, it replaces the conflicted region with that resolution.

Because the line numbers are shaved off before recording the conflict, this often—though not always—handles the recurring conflict. (It fails when the surrounding context changes, since this changes the hash ID of the conflict/resolution pair.)

It is a little bit dangerous since sometimes a conflict that looks the same, but occurs far away in a file, is not really the same conflict (this tends to happen with template-y code). Since every conflict and resolution gets recorded, you can accumulate a lot of resolutions and get false matches. Git tries to handle this by expiring recorded resolutions within 60 days (and unresolved conflicts within just 15 days).

You must enable rerere before creating the first conflict, and keep it enabled when git add-ing the resolution. This is a bit annoying since often you (well, I) discover that I probably should have enabled rerere earlier, and now it's too late. I have been tempted to write a script that repeats a previous merge or rebase that I have already resolved, using my existing resolution, to feed into a rerere-replay to prime the rerere engine. (The obvious name for this script is git-rererere... :-) )

like image 60
torek Avatar answered Sep 28 '22 05:09

torek