• Servers and Tools


From the class:  Git Merging

You should have a pretty good sense now of how git stores its objects in its database by watching the inside git class. I hope that gave you some intuition about what's going on under the hood. Now we're going to start to layer on some workflow concepts. One of the ones that you're going to use the most is merging in changes from other people, or maybe even from yourself, from different branches that you're working on on a project.

So what we're going to do through the rest of this class is talk about merging in changes through the merge feature of git and also through applying patches. So we're going to take a look at a couple of features of that, and then this kind of complicated-looking graph that will make a lot more sense to you by the end of this.

So let's start off in a project directory that's going to be empty. And I can initialize a new git project in this folder just by typing git init like we always have. That will go ahead and put a .git folder in here. And I'm going to just be using my Mac through this class. And so again, if you're using Windows, you might have to do things a little bit differently. But hopefully the concepts will be very similar.

Now, let's talk about what a merge actually is. And to do that, we'll start off by creating a file. I'm going to call it one.txt. And we're going to put some content into it using the command line. So I'll just call this the first line. And we'll echo that into a file called one.txt.

And then I'll add that and commit everything using the -a and the -v flag. And the -v flag will let me actually see what's in the commit. And I'll just call this the initial commit.

OK. Now that we have a file in our project directory, and we've made one commit, let's create a different branch. So pretend that you just got a request to work on a different feature. And so now we're going to create a branch to start working on that feature without affecting the master branch.

So I can check out and create a new branch all at once by saying checkout with the -b option. And I'll prefix it with feature since it's a feature. And I'll just name the feature one for lack of imagination. OK. Now I'm on feature one. And let's go ahead and add another file here. I'm going to echo out first line again, but this time I'll create a new file called two.txt.

And now if I look at the status, it should show that I need to add this file. There's something missing from the index. And so I can add the file like so-- add two.txt-- and then commit that change.

If I look at the log now, since I'm on feature branch one, there is going to be two commits. There's the initial commit, and then the commit we just made where we added a second file and added some content to it. Let's just pretend that while we were working on this branch, someone else was continuing to work on the master branch.

So we can sort of simulate that. I'll check out the master branch. And now let's look at the contents of our working directory. And note that there is only one file because we've moved back to the master branch. And I want to add another line to this file. So I will echo out-- let me just make sure I remember what's in it.

OK. So why don't we go ahead and add another line? I'll say, this is the second line. And I'll send that into one.txt with the two arrows like this. That will append instead of replacing. And now there's two lines of text. And I'll commit that all in one go-- I'll add it and commit it-- by using the -a option and then the -m option to provide the commit message right here on the command line. Added second line to one.txt.

If I take a look at the git log now, I'm on the master branch, and there's two commits-- the initial commit that I made and this one that we just made, where I added the second line to one.txt. There's nothing to do with feature one in this log. That's on a different branch. And so we're not seeing any of those commits quite yet.

I can see the log in slightly prettier format by using the --oneline option. That will show me the log all on one line, in a more compact format. Let's check out the other feature branch again and show that log so that we can see it in comparison.

And what I'd like to do is to draw out a chart that you're going to see a lot if you're doing any kind of research on the web. And I always find these drawings very confusing. So I'd like to walk through one so that you understand the notation that's being used, and maybe it'll actually help you see here what's going on and how to visualize the difference between the feature one branch and the master branch.

So we start off here with the initial commit. And I'm just going to abbreviate that with 200b. So this is the first commit, the initial commit. And then right at that point, we decide to branch. And so there's a branch that goes sort of this way on the master branch. And we'll just kind of call this top line here the master branch.

And on the master branch, we go and we add a second line to one.txt. And that's commit a70b. And sometimes you'll see these arrows pointing like this, which is quite confusing because it makes you believe that you should be reading from right to left. But actually, we're going from left to right. This arrow just means that this is a parent. So a70b comes next, and its parent is 200b. But we still read from left to right.

OK. But we also branched out. And in the feature one branch, we have another commit, this 26e9 commit, the add second files. So we've got another one over here, 26e9. And these two branches could continue by themselves indefinitely. So I could work on the master branch and keep committing, and this other person could work on this branch and keep committing. And we'd have these two lines of work proceeding independently.

So what happens when we use the merge command? Let's say we want to take the branch feature one, and I want to merge it back in to the master branch. So let's just label this so that it's clear. This is the master branch, and this is the feature one branch.

Well, during a merge, what git is going to do is it's going to try to find a common ancestor between these two things. And then it will figure out what the differences are between them and do its best to combine the changes into a new commit. So let's just call this-- I don't know what it's going to be, but we'll just say abc-something-or-other.

And this new commit is going to contain the changes between these two parents. So it's going to do its best to try to merge the changes between the two. And if it can't, it will tell you, hey, I gave it my best shot, but you're going to have to intervene as the user. So let's actually see that at work by using the command.

First, check out the branch that we want to merge into. So we want to check out the master branch. And we're going to merge the feature one branch into this one. So I'll use the merge command and then provide the branch that I want to merge into this one.

OK. Automatically, git is going to create a commit and open me up in vim so that I can put a commit message here. So this is kind of like if we had created the commit ourselves. But git has actually gone through and done a merge automatically for us. It's called a three-way merge, and it used a three-way merge strategy to do this.

And it combined the changes between the two branches, and now I'm sitting here in vim, and it's telling me to leave a message. So in the commit message, I'll just leave it the way it is. I've merged branch feature one into master. That should be good enough. And when I exit out or save and quit, we should have a new commit.

If I look at the log now, there should be all the commits. So we started off at the beginning one, and we've worked our way up to all the ones that were added in the feature branch and also the ones that were in the master branch.

Let's take a look at this commit because it's a little special. It's our merge commit. I'm going to look at its raw form by using the cat-file command. We're going to tell cat-file that we're looking at a commit and give it the first couple letters of the SHA-1 hash.

Notice that it actually has two parents, and that's the first we've seen an example of that. So it has two parents. It has the a70b as a parent. And the second parent is 26e9. 69 26e9. And that's here. And the reason that it has two parents is that the first parent comes from the branch, our feature branch that we're on. And the second parent came from the master branch.

So we were proceeding along. This was our initial commit. And then we proceeded along that branch. And then we had another branch over here. And I'll just call this A and B. And then we merged these back together into C. And so if it actually has two parents, like that.

So you see these arrows kind of going backwards? That's like saying-- this is saying that commit C has a parent A and a parent B. And specifically in this case, it's parent a70b and 26e9.