15

I got involved in a discussion recently on how to handle refactoring in general (which is an interesting topic in itself). Eventually the following question was brought up:

How does one handle merge conflicts that occured due to that someone did a refactoring of a part of the code, while someone else was working on a feature for the same piece of code?

Basically, I have no idea how to deal with this in an efficient manner. Are there any best practices that one should follow regarding this? Is there any difference on how one should handle this for a system with tons of legacy code?

1

7 Answers 7

12

Good question. The best strategy I can think of is:

Prevention

A combination of continuous integration and making small refactorings often (instead of occasional large refactorings) will go a long way to minimizing the cost and frequency of such conflicts.

5

If there's no active management of tasks, you have conflicts.

If, however, you have a daily stand up meeting or a manager, you cannot possibly have this problem.

Either talk (via a daily stand up) or talk to a manager.

This is trivially prevented by talking.

3
  • +1. Some developers see managers as an obstacle. But managers really exist to enable other people to work, and this is an excellent example of a problem they can help with.
    – MarkJ
    Commented Sep 16, 2011 at 12:21
  • @MarkJ: A manager that is an obstacle to merge conflicts is not a bad thing. Excellent point.
    – S.Lott
    Commented Sep 16, 2011 at 12:49
  • 1
    +1 I was just about to add something like this to my answer but you nailed it. If you're using a conflict to let you know someone else was working in the same area, you're going to find out very late in the game and then have to deal with it. Task management and communication can enable developers working in the same area to work together from the beginning.
    – Gyan
    Commented Sep 16, 2011 at 20:31
3

I think to answer your question, first we have to see why conflicts happen, and what is the true meaning and process of merging?

Conflicts occur only when two or more developers are working on the same file at the same time and then they both try to check in. The first developer won't get any conflict, of course. But the second (third, fourth, and so on) would get conflicts. Why, because (s)he has some code which is partially or entirely different from existing code on the server.

This in nature means that the second developer has something in mind different than first developer. This difference can vary from styling, like using new UserManager().GetUserName() instead of UserManager userManager = new UserManager(); userManager.GetUserName(); up to the level you mentioned, which means that both developers had different ideas of how to refactor the code to improve it.

Merging, on the other hand, doesn't mean that developers can check-in their code without considering conflicts. They should and must address those conflicts. If conflicts are not important, then they may check-in and override previous code. But when they see something entirely different, they should call the previous developer, and talk to him, so that they can both get coordinated together to check-in the best solution.

For example, if you ask two developers to improve online-payment library, and their work overlap, this means that at least on some places, there are 2 different solutions. So, one of those solutions should be talked about and be accepted, thus checked-in, as the better solution.

I don't agree on preventing these circumstances, as we should tend to be more real than theoretical. Sometimes a guy is really good at CSS, while another is really good at ASP.NET Markup. But their work may conflict when they should both work on login page to make it work. I mean, if we think real (not ideal), we can see that many times this phenomenon (conflict) happens.

Another point I just wanted to mention, is to use tools to help you in your check-in process. These tools usually visualize the difference of server code and developer code, and helps a lot in determining which part should be checked-in.

1

Have a separate common branch for developing a certain feature, merge/pull/push often - that's it.

And communicate. Speak with other developers about code even when launching. Even when coding )))

1

Make sure that the merge is as simple as possible. Refactoring is usually a rather mechanical process which changes many existing lines: Move variable declarations, whitespace changes, formatting, sequence of operations. Feature creation is usually a much more creative venture, often resulting in new code plus a few minor tweaks to the existing code. Now if the developer doing the refactoring records the steps (for example as regular expressions), it can be much easier to apply these to the code with the extra functionality rather than the other way round. Based on this, I'd say that as a general rule you should apply the most complex change first, followed by progressively simpler changes.

0

Revisiting this - my experience is that merging refactoring work is only a problem when there is code motion, such as:

  1. Extracting a superclass or interface.
  2. Extracting a method or variable.
  3. Moving a class or function into a different namespace / package / module.
  4. Splitting a large file.
  5. Condensing two files together.
  6. Renaming a file, usually with an associated rename of a construct.
  7. Sorting or regrouping constructs.

The problem occurs when work done on a feature in parallel changes constructs in their original location, but the refactoring moves the same code around to some completely unrelated place; merging doesn’t see the relationship between the original fragments of code, their changed forms on a feature branch and the moved fragments on the refactoring branch.

If you don’t have code motion, a straight merge with the odd bit of manual conflict resolution will usually sort it out.

Git can more or less handle an entire file rename in a merge, but anything more subtle eludes it.

Anyway, if you have to merge in refactoring work with code motion, Kinetic Merge may help.

I’m the author; this has been a perennial problem for me, hence my involvement.

0

At any point in time, there is a base line, you have code that is different from the base line, and merging changes the base line to include your changes.

Now if I had changes from the baseline myself, then I need to realise that the baseline is not the same anymore after your merge. So before I do anything else, I have to compare old and new baseline, and carefully integrate changes into my code, so that in the end I have functioning code that is based on the new baseline, and then I can merge it without merge conflicts.

Now most of the time "merge conflicts" just mean that an automated tool doesn't know how to perform the merge. A very common situation is that you added a new function, I added a completely different new function to the same file, and we both added the function at the end of the file. There isn't really a logical conflict, it's just that the automatic merge tool cannot handle two different functions being added in the same place. (It can handle two calls to these functions added in different places). Or you added a function parameter, I added a parameter to the same function, and if we want both sets of changes, then both parameters are needed. So since I am significantly more intelligent then any merge tool, I can fix this manually.

It's rare that we have real conflicts. Again, we may have both added the same parameter because we both needed it, but gave it different names. That's a real conflict, but easily fixed by changing my parameter name. Or we both changed a horribly bad and misleading identifier that needed fixing, and changed it in different ways; same thing. And there are real real conflicts. Like the maximum for a value was 50. You were told that the maximum should be 60, and I was told it should be 70. Now something has to give. At that point we need to discuss why you chose the number 60 and I chose 70 and which one is actually correct.

But the principle is: A merge must NEVER have conflicts. You change your modified code before you merge so that it is based on the new base line and gets merged without conflicts.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.