Check out a free preview of the full Everything You'll Need to Know About Git course

The "Merge" Lesson is part of the full, Everything You'll Need to Know About Git course featured in this preview video. Here's what you'd learn in this lesson:

ThePrimeagen explains the concept of merging in Git and discusses the two different outcomes of a merge - one with a merge commit and one without a merge commit. He also explains the concept of the best common ancestor and how Git combines the histories of two branches during a merge. The process of merging branches using the `git merge` command and examples of merge commits and fast-forward merges are also covered in this segment.


Transcript from the "Merge" Lesson

>> With the previous section, you should have this setup. Hopefully everyone has this setup. So now we're gonna need to do the exact same thing to trunk, except for we want to have D and E. This time, I do want you to edit the readme file. So the readme file will contain three changes now A, D and E, then we'll have a second file called

That's only a on foo. So, to be able to make these changes, you first have to checkout trunk. Now you need to make these changes one at a time on the trunk. So I'll use the identical process here. I'll do D and this is gonna go to README.

I will add it. I'll commit it with the message D, very important to do that. I will now add the next commit which is gonna be E, add it to README, stage it and then commit it with the same message. So now if I were to do a git log, I'll do one line this time.

You will see trunk points to E, which has D and A in the past. I can actually use git. Do you know you can use git log with a with a branch name so I can do foo. And you'll see foo C, B, A. Perfect, so we have these two setups now, I can see trunk is correct.

I can see foo is correct and I have this setup right here. So now it's time to merge these two together. There's actually two different ways you can do it. There's merge and there's rebase, we'll go over rebase at some point, but we're gonna start first with merge.

Now remember, a commit is just a set of changes in the entire code base at a specific point in time. And if you have work on one branch and you get it over to another branch, we're gonna use merge. Now, the thing about merge that's a little bit confusing is that when you use merge, you can have two different outcomes.

You can have one that has a merge commit and one that doesn't have a merge commit. And you probably experienced this where sometimes you merge and you have to input a message and then sometimes you merge and you don't have to input a message. And there's a very specific reason why it depends on your history.

We'll go over that in just a little bit, we'll create the two situations which exist. What is a merge? A merge is just attempting to combine two histories that may or may not have diverged. Diverging means like how we set it up. A is in the past and we both share A, but there could be zero or more commits in both branches that cause us to diverge.

Now, whatever you are merging get used to something called the best common ancestor, which is gonna be the first in common commit. So for us, we have A, B, C and we have A, D, E, A is the best common ancestor. In the docs, you'll often see it's called the merge base, and so really, it's just the first thing that's in common.

So if you were to walk up the tree, if you were to think about it, you having to write this algorithm, you literally start at each commit. And you just keep on walking the parents with a hashmap. By the way, you'd wanna use a hash map here on ironically.

You'd use a hash map to contain or it's really a set to contain all the commits you've seen up to this point and the first time you have something that is in common, you've just found the best common ancestor. Funny enough, it's always a hashmap. I don't know why, but it's just always this.

And so, git then takes these two commits that you have, checks out the merge base or the best common ancestor, then plays those commits on top of it, creates a new commit called a merge commit, and that will actually have two parents. You'll have one parent from one branch and one parent from another branch, and that is a merge commit.

This happens, that's what you'll get a message cuz you have two different diverging branches, so we'll go over that. Here we go, all right? So, how to merge very, very easy. You have a target branch, which is the branch you are on and you have a source branch.

The one you wish to merge with, and the source branch is gonna be the one that you provide the name. This is how I think about it at least. I think this is probably the the easiest way to think of it. And so you'll do git merge the branch you wish to bring onto the one you're currently on.

So let's do it now. Let's merge foo onto trunk, but remember we don't want to ruin our current trunk state, so I want you to check out a branch called trunk-merge-foo. So, I'm gonna go git checkout trunk-merge-foo. Have my new branch, remember- b just creates a new branch if it doesn't exist or, awesome.

So now I'm gonna go git-merge-foo. There we go. We'll present this menu saying, hey, we need you to merge this together. We want you to add a commit message. It's been auto merged for you, but we still need a commit message. Remember, a commit is a series of changes.

That represents the entire state of the repo, plus an author, plus a message and time as well. You probably see something like this, merge made by ort strategy. That's relatively new. I think at one point it used to say like a three-way commit strategy, and now it's changed into the ort strategy.

All right, so when we're done, I want you to use git.log. So everyone that has just merged, use git.log and see what happens. And I also want you to use the term parents when you do git.log or git.log. When you do git log I want you to add--parents.

So show the parent commits along with everything. So I'm gonna git log --oneline --graph --parents. So you can see right here the merge commit has two parents. If you look at this ID this sha you'll realize this is trunk where trunk is currently pointing to. When you look at this one, this is where foo is currently pointing to.

This is C, this is E. And then now, with the graph, it's able to draw this nice graph because it has all that information. It's able to walk back the graph and be able to display it for you so you can actually see in line what is happening.

So there you go, that's pretty neat, right? By the way, log, totally underrated. Super cool, super cool utility to kinda know some of the things to use. All right, so now I want you to create the following git setup. I want you to check out trunk, then I want you to check out a new branch called bar, and I want you to add two commits, X and Y.

And X and Y, please put the changes into a file or just some other file that's not README. I used So I'll do it with you, git checkout trunk, git checkout -b bar. I'm gonna echo in x into I'm gonna add it. I'm gonna commit it.

I'm gonna do it again with y. All right, so we've now created this right here. It's pretty straightforward. All you have to do is just checkout bar, add the two commits. This is almost identical to what I just got done doing on the screen pretty easy. So we should now have the exact same thing.

We should be able to use git log to see that we've done this correctly. So I'll do it right now. And we'll use the exact same git log, that we're always using with one line and we can erase parents who don't really need to know parents, but you can see here, bar.

Is that Y trunk? Is that E? Can you say anything that's unique about the situation that wasn't unique in foo or that was different foo, shall I say? What's different between this setup versus what was done with foo and trunk? Foo and trunk, both diverged, in this situation bar is the only one that has diverged.

Its best common ancestor is the tip of trunk. It's very important thing to remember or to observe, shall we say. So now let's merge bar onto trunk. So do the exact same thing and this time we do not create a separate branch, just checkout trunk and merge bar onto it.

So I'm gonna go git checkout trunk, git merge bar. And you'll notice this time there's no commit message. Why is there no commit message? Again, the best common ancestor was the tip of the branch you are merging onto, which means that it can just take the commits and just update the pointer.

That's all, it doesn't have to do any sort of merging. It already works. You've already resolved any conflict. It can just simply fast forward the merge. So you'll often see in the documentation where says, ff-merge It literally means you have a linear history with no divergence and you can just simply take the commits and update the pointer.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now