It’s going to happen one day. One of your students tries to merge one branch into another, and the dreaded error appears:
CONFLICT (content): Merge conflict in filename.ext Automatic merge failed; fix conflicts and then commit the result.
When changes in two branches overlap, Git shouts out for a clever human (like you or one of your students) to reconcile the differences. Even if you follow all the best practices of Git—communicate with your collaborators, pull in changes regularly, and make commits that are small, logical chunks—merge conflicts can still happen.
But merge conflicts don’t have to be scary for you or your students! In this post you’ll learn how to help students resolve them.
There are many situations when a merge conflict can happen—when a student pulls in changes from a repository, after they open a pull request, or when they push changes to another repository (there are other, less common situations too, like unstashing, cherry picking, and rebasing, that won’t be covered here). Let’s look at a few examples:
git pullto bring in their teammates’ work, they find that they’ve made overlapping changes to the same file.
Each of these situations leads to a merge conflict, but the process for resolving them is similar.
When Git encounters a conflict, it pauses whatever it was doing (like pulling changes) and asks you to resolve the conflict. To help you sort out the situation, Git inserts conflict markers into your files, showing you what your changes are and what your collaborators’ changes are. Conflict markers look like this:
<<<<<<< HEAD See also: [re docs](https://docs.python.org/3/library/re.html) ======= See also [re docs](https://docs.python.org/3/library/re.html) >>>>>>> master
In this example, Students Frank and Helen have both modified README.md. Frank’s change has been merged to master while Helen’s changes are on a local topic branch. Helen discovered this when she tried to merge the changes from master into her topic branch.
Helen looks closely at the conflicting line. Both students have made roughly the same change to the file by adding a link, but Frank’s change includes a typo. Helen decides to keep her version (HEAD) and discard Frank’s (master). She does this by deleting Frank’s changes and the conflict markers, like this:
See also: [re docs](https://docs.python.org/3/library/re.html)
When she’s done resolving the conflict, she runs
git add README.md to tell Git. Satisfied with her changes, she runs
git commit to finish the merge.
Consider another example, however, where Helen and Frank have both changed the same line in different ways. Before either of their changes, the file they’re both working on contains this line:
Don’t forget to run the `linter!`
In this example, Frank has expanded the sentence while Helen has added a filename. Helen pulls in the changes and sees these conflict markers:
<<<<<<< HEAD Don’t forget to run `linter.sh!` ======= Don’t forget to run the `linter` for :100: source style! >>>>>>> master
It doesn’t make much sense to choose one side over the other, so Git offers another option: write a new line that wasn’t in either side’s commit history. Like this:
Don’t forget to run `linter.sh` for :100: source style!
If there are more conflicts, then Git will insert conflict markers for each conflicting chunk it finds. Resolving many conflicts is like resolving one, except there are more conflict markers to tidy up. Walk through them one-by-one to resolve all the conflicts in all of the affected files. When you’re finished, add the files and commit.
Sometimes you’ll see a merge conflict in the context of a pull request.
A conflict in a pull request is like one on the command line. In a pull request, you can discuss with your collaborators how you plan to resolve merge conflicts and revise your branch.
The first option: the pull request author can update their branch. Since pull requests work with branches, you can often resolve a merge conflict by adding one or more commits to the incoming branch. For example, you can merge changes locally (e.g.
git merge master) and push the branch with the newly-added merge commit to GitHub.
If it’s a complicated conflict, you can discuss the best approach right from the pull request comments. Alternatively, you can amend your pull request (for example, by rebasing the incoming branch or amending a previous commit). This can be confusing at times, especially if there’s already been discussion in the comments.
Another option is to let the person accepting the pull request resolve the conflict while merging it. You can do this within the web interface using the GitHub editor or with the command line instructions GitHub provides—either way, it’s just like resolving a conflict with Git alone by choosing the resulting lines and removing conflict markers.
Resolving merge conflicts under a deadline might not be the best time for students to learn about them. Deliberately introducing merge conflicts in the classroom can help students when it comes time to handle them on their own. Check out Dr. Mine Çetinkaya-Rundel’s talk in which she shares how she teaches students Git skills, including resolving merge conflicts.
Want to learn even more about helping students understand and resolve merge conflicts? Check out the Campus Advisors learning module #3. This video course will help you learn more about group work, pull requests, and how to get your students comfortable with resolving conflicts.
Do you have an assignment you like to use to teach merge conflicts? Let us know in the GitHub Education Community.