We use a branching git workflow, but we have real issues with merge conflicts. None of us are git gurus so we always end up manually resolving the conflicts in an IDE which is error prone.

There has to be a better way? We have 4 teams, all with 5+ devs working in the same (very large) codebase.

We branch off master, do our work then open a PR to master when its done, but in the mean time another team could have a PR merged to master in the same code we were working on. Here we have to get latest of master, and merge it into our branch, resolve the conflicts (never easy) then push and then we can merge our PR to master.

Firstly - is there any easier way to deal with conflicts such as this. Secondly - would a forking flow help, and if so, how?

  • If you want a shared codebase again some time in the future, forking is a bad idea. You just move the problem of resolving conflicts to the future, where it becomes magnitudes harder than resolving the conflicts right now. I find it a little strange that it happens regularly that several of your teams edit the same code and create "never easy to resolve" conflicts. Maybe, the responsibilities of the teams need to become more separated. Or maybe you need to create more pull requests with smaller changes. For how long do you work on a branch until in gets merged into master again? – pschill Oct 12 at 9:50
  • we have had one branch about 3-4 weeks now, other teams longer. it can be hard to break things down smaller as they need tested, then retested when we add another feature... I know thats not ideal but the business want to test features as a whole and we don't have a QA team – user3437721 Oct 12 at 13:23
up vote 2 down vote accepted

There is no way to always prevent merge conflicts, but it is possible to minimize them.

  1. Communicate. Everyone who works on the code base should broadcast their intention to work on a specific part of the code. If two people will work on the same part, they should find a way to proceed:

    • For example, their changes may not conflict at all or only have minor conflicts. Then they can just continue as normal.
    • Or maybe they can do some preliminary work to refactor the code in such a way that their changes will not conflict.
    • In the worst case where the changes will have major conflicts, it might be better to first complete one person's work and only start the other changes on top of that.

    In part, this is a project management problem. Avoiding merge conflicts is better than resolving them, and this starts by allocating different work to different teams.

  2. Keep a tidy, well-designed code base. Most pull requests should only touch a few files, and not require huge changes across the project.

  3. If there is a huge cross-cutting change such as large refactorings or introducing a new framework, halt any other development on the codebase in the meanwhile. First plan the refactoring, then merge any remaining pull requests that would conflict, then quickly apply the refactoring, and afterwards resume normal development. Since software development involves more than writing code, other developers will likely not be bored during this time.

    If you do not halt other development during such huge changes, you will likely have to do the work twice: first on top of the old code base, and a second time on the refactored code base.

    Of course, huge cross-cutting changes should be rare in a well-designed code base. It is often possible to instead refactor one component at a time.

  4. Keep pull requests small. Merge early and merge often. The earlier you merge your code, the fewer other changes will there be in the meanwhile. This also means that a PR does not have to be a complete feature, but can also be a partial feature. It is OK if a PR only contains a single commit, or changes only a few lines. Those are in fact easier to merge and review!

    Goal: try to create PRs that contain the work of a few hours or days, not weeks or months.

    If work on a feature leads to related changes such as a bit of refactoring, that refactoring can be merged independently! So, do any refactoring first and merge it in a separate PR from your main feature.

  5. If a feature is not ready to go into production you might still want to merge it early. In that case, disable the incomplete code using feature toggles. This way, it is still compiled and tested, and other people can build upon these changes. Once the feature is complete, remove the feature toggle.

  6. Avoid techniques like cherry-picking individual commits into another feature branch, or branching a feature from another feature branch. These seem easier at the time but make merges more difficult down the line. If you need changes in another branch, first merge those changes into master and then merge master into the other feature branch.

    While working on a feature branch it is not always obvious what changes should be done first. If you realize during your work that you are doing refactoring that should have been done in a separate PR, you can rewrite your branch history (git rebase --interactive) to re-order your commits, and then issue a PR for your first few commits.

  7. Merge PRs quickly. Smaller PRs can be quicker to merge, but now you likely have much more of them. If only a few developers are allowed to merge, those few will lose a lot of time on that. An approach that can work very well is if everyone is allowed to merge anyone else's PR. For each PR that someone submits, they can review another. Ideally PRs are merged within one or two days.

Better tooling cannot prevent merge conflicts, but can help you resolve merge conflicts more easily. This is largely a matter of personal preference. It is possible to resolve conflicts in your normal IDE where you search for Git's conflict markers (<<<<<, =====, >>>>>). Your IDE might also offer a special merging view that shows the conflicting versions side by side. Alternatively, you can use an external merge tool. I use a separate tool that allows me to do a three-way merge: the merged file in the middle, with the conflicting changes on the left and right. Differing lines and differing words within a line are highlighted.

Forking will not help. As far as Git is concerned, multiple branches in different repositories are basically the same as multiple branches in a single repository. This is part of Git's distributed nature. When people use multiple repositories, it is usually just as a matter of access control, so that you don't have to give everyone write access to your repository. Within a company this is irrelevant, and any pull-request based workflows can be implemented within a repository.

  • This is a good summary and it helps me realise it the process, communcation at fault and not our tooling or git strategy – user3437721 Oct 12 at 13:25

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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