• Servers and Tools

Fixing Conflicts

From the class:  Git Merging

There's a lot of scary things in life, and probably one of the scariest is having to fix a getmerge conflict. So in this video, I'm going to show you how to do that.

To illustrate the issue, let's start off by creating a new branch. I'm going to call it conflict to make it simple. I won't even prefix it with feature this time. And inside of that branch, let's make some changes to a few files. So I'll start off by changing one.txt. And I'll add a little bit of text. So we'll say "updated from conflict branch."

And I'll save that. And then let's update one more file. So we've changed two files here from the conflict branch. And then I'll save that and quit out of the editor. I'll commit this all in one go, "updated from conflict branch."

And now I'll check out the master branch. And let's make some changes-- oops. I got to say which one I want to actually check out. Let's make some changes on the master branch. And you can imagine that this would happen because two people are working on the project at the same time on different branches, and one person is making changes to a set of files in their branch, and then somebody else is making a set of changes to those same files on the master branch.

I'll open up the same files as we did last time, except I'll just say "updated from the master branch" to make it simple to identify. And let's make two changes here. OK so I've updated the same two files. And I'll commit those changes on the master branch, again, in one go.

And now the moment of truth. I want to merge in the changes from my conflict branch. So I'll use the merge command like we have before, and I'll merge in the conflict branch. And here we are, presented with the deadly merge conflict message. So now what we need to do is to fix this.

A couple things to note, first, from this message-- it's telling us which files have conflicts in them that we need to fix. And also, notice that in our status bar here, if you happened to update your command prompt, it's telling us that there's files that are different in our working directory than what's in staging. And it's also telling us that we're in a special merging state.

If you accidentally lose this information or close the window, don't worry. You can always type git status. And that will tell you which files are currently in conflict. So find the section here that says unmerged paths, and it will say that we need to fix these or resolve each one of these files. And then when we're done, go ahead and add them to the staging area or to the index, and then we can commit the result.

Before we fix the conflicts, let me show you a couple more things. If you use the diff command to see the difference between our working directory and the index, notice that git has checked out these files and created some annotations. And the annotations are intended to tell us what the conflicts are between the master branch and our conflict branch. I'll walk you through this in more detail when we open up the files, but I just wanted to show you that git has done something automatically here. It's checked out some files and made some updates to those files so that we can go through and fix these conflicts one by one.

The other thing I want to show you is if we look inside of the git directory, I'm going to search for anything having to do with merge. So MERGE*. And then also, we'll take a look at the head. These are files that are in our git folder. And just like you saw previously, the head file is going to point to some branch. In this case, right now it's pointing to our master branch.

And then we have some files that are related to this merge itself. If we take a look at the contents of the merge head file-- I'll just use the regular cat command here-- notice it's pointing to a commit. And that commit is actually the branch that is in conflict. So this points to our conflict branch. And we can verify that by using the cat-file command of git.

So I can say cat-file pretty print. And we can just type MERGE_HEAD directly. It will know what to do. And notice what comes back is our commit message from the conflict branch. You can see it because of the message that we left here. But we could also just verify it against what happens if we take a look at the conflict branch. And it should be the same thing. So they're pointing to the same trees, and it's the same commit message.

So the merge head points to that commit from the branch that has the conflict. And then it checks out the changes to our working directory along with these annotations that show us what the actual conflicts are. Now, let's say you make a mistake. And you find out that there's 100 files that need to be fixed, and it's going to take you all day. Well, you might just want to abort this process altogether.

And you can do that easily. Just say get-merge and pass the abort flag. And that'll revert the changes and land you back on the master branch or whatever branch you started on before the merge. So you can always use this as a last resort if you need to to get out of this process.

Let's go ahead and fix these conflicts one by one. So open up vim, and we'll start off by looking at one.txt. Git uses some special symbols to alert us to the conflicts. And they're easy to see here because it's such a small file. But if you had a big, giant, long code file, you might have to use VAMT or whatever tool you're using to search for these special characters or symbols.

Let me walk you through what they mean. It'll start off with these open carrots, and then right after that, it will use the symbolic reference that we're currently on. So head right now points to master. And that's the current branch that we're on. This could point to some other branch if we were on a different branch. But right now it's pointing to the master branch. And the content that we see between that and this equal sign is the content that's on the master branch.

Then after this equals comes the content that's on the other branch. And it ends with a bunch of greater than symbols here. And it tells you the branch that it came from. So the identifier up here is the current branch that we're on. And the identifier down here is the branch that we're merging in that has the conflict. And then all the other content that's outside of these annotations is common content between the two.

So our job right now is to figure out what to do. We could just keep both of these pieces of content, or we could choose one or the other. It depends on the circumstance. In this case, let's go ahead and just keep both lines. So I'll keep both, and then get rid of the annotations that get left for us. And now we have a fixed conflict.

Let's open up two.txt and do the same thing, except this time, I'm just going to go ahead and keep what was in the head, in the master branch itself. So I'll get rid of this down here, and then we'll get rid of the annotations. And we're left with the first line updated from the master branch.

I'll save this file and quit out of vim. And now what we need to do is to add those files to the index. Right now, we've changed them in our working directory, but we haven't added them to the staging area. And we need to do that manually.

So I can say git add one.txt, and then git add two.txt. And we can take a look at the status. And notice something a little peculiar here. It says that one.txt has been modified. And it's also in the staging area, so the green kind of tells us that.

But two.txt got isn't in the list. And that might be a little confusing. The reason is because remember we got rid of the change that came from the conflict branch. And now the two.txt text file, what's in the index and what's in our working directory is the same. So there's nothing actually to fix here.

Now, once we've added the changed files into the index, we can make a commit, just like we would do normally. I'll say git commit, and then -v so we can see some changes. And now we get our normal merge branch conflict commit message. And when I save that and quit, our merge has been completed.

Just like with a regular merge, once it's been done, we can look at the results-- git log and take a look at the graph. And I'll just say one line to make it easier to see. And we have our merged commit that we created with the last commit. And it has two parents, one from the conflict branch, and the other one from the master branch.

And also notice now that the merge process has completed, if we look in the git directory for those merge files, they're gone. They're just completely gone because the merge process is completed. So they're not needed anymore. And if we look at the head file, it should still point to our master branch or the latest-- and master branch, in turn, points to the latest commit on that branch.