Pergunta

I'm a beginner at collaborative development, I started learning about merge conflicts. And I have this question.

Is it possible for a developer to deliberately postpone merging because he doesn't want to be the one resolving a potential conflict?

If this isn’t the solution, what are the strategies that work?

Foi útil?

Solução

Oh god yes.

I broke the build my first time. Made me so gun shy I was hiding versions in folders. Of course delaying my check ins just made things worse. I was in hell until I figured out what I needed.

I needed a safe place to play.

I created my own toy project so that I could deliberately cause merge conflicts. Learned how to fix them the hard way. Soon people were asking me to help them fix their problems. All because I took the time to play with a toy.

Check in often. It will keep what needs fixing small. But take the time to learn your tools so you can see trouble coming.

Outras dicas

In general, individual developers will be responsible for merging their own work. Delaying things only means it's more likely for others to get code into your merge target, making the merge worse.

Extreme Programming is (partly) based on the idea that if things are "hard" or "scary", we simply aren't practicing them enough.

That's the thing: practice makes perfect.

So, the approach that Extreme Programming takes, is that things that are hard should not be pushed back as far as possible to avoid them. Instead, they should be embraced and done as early and as often as possible so they become familiar and lose their "scariness".

Not only does doing things often make them familiar and gives you practice and experience, so that you get better at solving the problems you encounter, but at the same time, the problems get smaller!

Releasing is scary because after a year, you have forgotten all the steps and scripts and magic folders? Don't just release once a year, release every week! Not only will it help you remember all the arcane scripts, all the steps, all the magic folders, it will also force you to think very hard about whether all those arcane manual steps are really needed or if they can be either eliminated or automated.

Code review is scary because there is always a mountain of code, and it takes endless hours? Do it continuously while you program (pair programming), that way, there is always only one line of code to review and the review only takes half a second or less.

Merging is scary because there are always huge merge conflicts and it takes hours to resolve them? Merge as often as you can! Again, not only will you get better at merging by doing it more often, but also, the merge conflicts get smaller! If everybody on your team merges 5-10 times a day, how far can your code really diverge in that time frame?

So, let's say by merging often and gaining practice and experience, you become 3 times better at merging. (It's probably going to be even more than that.) Also, let's say that by merging more often, your merge conflicts become 3 times less frequent and 3 times smaller.

That means that merging becomes almost 100 times less scary.

That is the XP approach, at least. It works even if you don't follow all practices of XP, although of course all the practices are meant to work together and link into each other and reinforce each other.

Yes and no

In my experience, merge conflict are a result of not communicating. If you plan properly, you and your colleagues shouldn't have many merge conflict.

The reason people 'fear' them, is because it can be a puzzle to un-conflict them. Sometimes it's just 1 or 2 lines, but it could be a lot, multiple conflicts in one file, because you and a colleague had to work in the same file, both working/refactoring some code. Those can take time to unmangle again and if you do it wrong, the work of party A, B or both stops working properly. The bigger the conflict, the more testing needs to happen afterwards, and most are not fan of testing that extensively.

There are a few way to minimize merge conflicts:

  • Make small PRs/commits; Just make tiny adjustments. The smaller the changeset, the less merge conflicts can exists in the first place.
  • Make small PRs/commits; Small PRs can be merged more quickly, that means they dont get outdated that quickly. This also means that others:
  • Merge the master(or leading working branch) often into your work. You'll get new code (and possibly some fixes) more often and can reckon with others.
  • Talk about who does what in a job, possible decided that feature A is easier if B is made.

The difficulty of a merge grows with the square of the number of merge conflicts. So it doesn't matter whether you fear merge conflicts, you resolve them as soon as you can.

Where I work, you branch from the development branch, make changes to your branch, and create a pull request. If the pull request has merge conflicts then it is your job to merge the current developement branch into your branch to remove the conflicts. So there's no way that merge conflicts in your code go away without you resolving them.

Best strategies are:

  1. If your development takes time, merge the development branch into your branch from time to time. That keeps the merges, even with conflicts, a lot easier.
  2. In cases like bug fixes, where 90% of the work is finding the problem and 10% fixing it, create your branch only when you start fixing, that reduces the chances of conflicts.
  3. If someone wants to do some refactoring that is likely to create large numbers of conflicts, organise things so this doesn't happen while other long-term branches are opened. Pick a time when all big changes are merged and do the refactoring as quick as possible.
  4. Don't add new functions at the end of the source file or header file, but at the place where they belong. That's because if we both add things at the end of a file, we'll have an avoidable merge conflict.
  5. If you use an IDE that makes changes on its own, make sure that all developers set up their IDE in an identical way, to avoid unnecessary changes leading to unnecessary conflicts.
  6. If you have files that are modified by tools creating lots of irrelevant changes, only start changing such files after agreeing with others that they are not touching them at the same time.

Do developers fear merge conflicts?

Hell yeah. It didn't help that one of my two senior engineers was built like a linebacker. Grey hairs and balding but shoulders and neck merged together like a linebacker without fat, just epic traps, always spotted in the gym doing bench presses and deadlifts with veins popping out of his forehead, while joking around that he'd kill anyone who breaks the build.

But you know, social stuff. I remember being fresh out of uni and being afraid to talk to people. What a load of bollocks now in hindsight. Talk to people. We might not all be the strongest that way being the types to imagine worlds in our computers. You try and get better. Don't delay a merge. Talk to somebody. Get over the fear. You don't have anything to fear if you talk to people all the time.

What makes people upset usually is unpredictable stuff. There was no heads up. That's how I get upset anyway and that's how lots of people seem to get upset. So it's not the merge conflict that ever pissed me off. It's a merge conflict with someone who never gave me that heads up. Communication is the solution as hippie as that sounds.

Actually, I just revisited your question and one part confused me:

Is it possible for a developer to deliberately postpone merging because he doesn't want to be the one resolving a potential conflict?

If you postpone your merges you get more conflicts, no? I would think it would be more tempting to rush merges to avoid conflicts and bounce them to other people making changes to the same code. If you postpone, you tend to defer more conflicts to yourself. As one who started out passive and very shy and not wanting to interfere with anyone else's work, I used to do that. It's like I didn't want to inconvenience other people on my team so I would postpone my merges and resolve their conflicts so that I wouldn't introduce conflicts to them. In hindsight, I think just talking to them was the superior solution.

There is more than one kind of merge conflict, and most of them can be trivially resolved because to a human it is obvious what should happen, but to the computer it's not.

Strategies for resolving these:

  • rebase everything instead of merging

No merge commits, ever. Instead, a branch is tested on its own, and when it's ready for submission, it is rebased first. This way, you are presented the conflicts of new commits on the branch individually rather than all at once, that is a lot less work.

  • rebase slowly

My favourite git command these days is

for i in $(git rev-list --reverse $(git merge-base HEAD origin)..origin); \
do \
    git rebase $i || break; \
done

This will rebase the current branch by moving ahead one commit on "origin/HEAD" at a time, stopping on conflicts. That way, you can only see the conflicts introduced by two commits, not "one branch and one commit", so it should be significantly less. If it stops, resolve normally, continue the current rebase and then run the command again to get back into the loop.

  • enforce coding style in separate commits

Conflicts between a functional change and a whitespace change can be resolved by adding whitespace change commits and merging them separately.

The truly difficult conflicts are a matter of failure to communicate with other developers -- someone removing an API that another is using. One thing I do for refactoring commits is to split them up into

  1. add new API
  2. move component A to new API
  3. move component B to new API
  4. move component C to new API
  5. remove old API

That way, the last commit can go into a separate merge request, and I can ask other developers if this is okay to merge yet or if it breaks their branches.

A nice tip to make merge conflicts easier.

git config --global merge.conflictstyle=diff3. Without this set you will see your code and their code only. With it being set you will also see the original. For more info see this StackOverflow answer. Here's an example. The first is what it would look like normally.

<<<<<<< HEAD
log.info(String.format("%s entered password: %s on attempt %d", user, password, attempt));
=======
log.info(user + " entered password: " + mask(password));
>>>>>>> blah

Compare to this which is what looks like with it on.

<<<<<<< HEAD
log.info(String.format("%s entered password: %s on attempt %d", user, password, attempt));
||||||| merged common ancestors
log.info(user + " entered password: " + password);
=======
log.info(user + " entered password: " + mask(password));
>>>>>>> blah

Now it is more clear. Comparing the middle (the original) to the bottom (the incoming) we see that they masked the password. We should do that in ours also.

log.info(String.format("%s entered password: %s on attempt %d", user, mask(password), attempt));

Code formatting standards

(Partial answer, just adding to others.)

This may sound stupid, but in my experience a lot of merge difficulty (I've seen quite a few instances of regression and new bugs introduced way back...) was caused by code format changes between different developers and the merge tool not being syntax aware enough to handle them gracefully. An easy answer is to simply enforce a coding style/format standard with little or no discretion left to developers. One example would be the Google Java Formatter, which can also be hooked into your build or check-in process so that it is simply automated and no one can "forget" to do it. (A compromise format that all developers can agree to, even if grudgingly.)

This is a "low-hanging fruit" that will go a good way to ease some of the pain, in addition to the techniques put forward in other answers.

They are complete disaster, because fixing them wrongly may result the code that ok compiles but now contains bugs (lost or duplicated lines that are not declarations often do not break the build itself). They also take lots of valuable time to fix.

Any technical improvement that would allow to solve merge conflicts easier or automatically is the most welcome. I also think that some organizational approaches should be taken to minimize the possibility of the merge conflicts.

Even when I handle a repository where I'm the only collaborator and have multiple branch, I really avoid having to switch branch mid work, unless of course it can't be avoided.

The horror of doing the switch ASAP due to something urgent and just commit the change first then switching, then suddenly something weird on the list of changes pops up, this happened to me yesterday, it was the worst, like the last x minutes during your instant commit flashes before your eyes, and I try to think hard and stay cool but inside I'm like "wtf, I just committed everything why there's still something on the change list!!!"

My personal advice when you do encounter conflict and have to merge is to really do it calm and collected, really focus and don't try to shortcut or do this ASAP like I did, also when handling other's codes be sure to know what they've been doing and if needed, contact them.

Merging can be a silent killer since everything will run correctly because after merge, you'll compile it until it works on your side thinking maybe the merge did something to your code if any error occurs, people tend to focus on their work hence we often forget merging means someone's work is now in our hands.

Licenciado em: CC-BY-SA com atribuição
scroll top