Merging code can be challenging and is not where the fun is. Git will follow through with many algorithms to identify how changes can come together as intended. However that is not always possible.
I'd like to go over some challenges I'm seeing, how I deal with merge conflicts, and how to avoid them.
There are some really good merge tools out there. Then there are others which work but can make things harder.
Personal choice of editor is vim, and I've come to like diffconflicts as I get the benefit of the auto merge with the focus on conflicts.
Beyond Compare comes to mind as another good tool. Kdiff has to be the worst tool I've used, so maybe check out meld.
I find one of the most important aspects to handling merge conflicts is to have sain commits with clear expectations of the end result. If your commit is "made things better" and handles refactoring, performance, and fixes a bug it will be hard to identify what is needed in the face of a conflict.
This is also beneficial on the other side, when you conflict it is with another change, one that someone else may have author which you've never seen before. Understanding their work is easy with smaller commits.
This is where I had the mental model wrong for a little bit and is the reason I wrote this.
The reason people have been emphasizing this snapshot mental model has everything to do with the conflicts. I do not want to spread incorrect information but this is the best explanation I have so far for things I've seen.
Git will conflict on files, this means files that only change from one branch will not conflict. But this also means it will conflict outside the changes of the commit and identify all file differences. Since I view this as an odd behavior, there is probably some heuristic at play and maybe I've misunderstood some of my conflicts.
I recommend looking into rebase's rerere option. I still need to use it to make commentary.
I've been told that merge doesn't care about commits and just diffs the final state. That is probably the same thing happening in rebase per commit. Just in a rebase I think "change" and git thinks snapshot.
There is only one true way to do this, don't change the same file on different branches.
There are however techniques that help reduce the likelihood of a conflict and you've probably heard of it, Continuous Integration. This term is overloaded but it's heart is to commit to a shared mainline a work with latest mainline updates.
Git provides rebase as a way to keep up with mainline. Conflicts will happen, but if you have the latest changes for a file your about to change you'll at least avoid one conflict.
Remember, the sooner you get your change merged in the more likely someone else has to deal with the conflict, and you give them a chance to stop it before it happens.
Sometimes when rebasing to stay up-to-date you haven't cleaned up the commit history, this is not the time to do that. If you have too many commits then necessary consider
git rebase --abort and clean up the history on the original branch first.
It may also make sense to not include certain commits, hopefully you've been pushing up isolated changes but realistically it does not always happen that way. So find the conflicts you'll deal with later and put them in another branch.
I reorder commits a lot and this can create conflicts within the same history, be sure to deal with these before combining work.
Give up and squash it all. Sometimes it can just be easier to deal with it all at once and you can break apart commits after rebase is complete.
If you first refractor before fixing something, get the refactoring merged in first, fix the issue before refactoring, or don't refractor it might no be worth keeping.
All of this relies on understanding what is changing. If you program by throwing changes in until it works but never understand why, expect conflicts to haunt you. If you follow what I've laid out, expect that learning to merge has just started.