GIT: Branching and Merging
This course is an introduction and overview of branching and merging with GIT. By the time you complete this course, you’ll be able to understand what it means to create branches locally or at a remote repository. You’ll have a great command of keeping your branches up-to-date and cleaning up both your local and remote repository.
By the end of the course, you’ll be in command of working with teams at GitHub and using Pull Requests to validate changes by multiple developers. You’ll know how to make sure you get their changes as well, and finally you’ll be able to resolve merge conflicts locally and at GitHub.
Why should you learn the command line when tools are available like Visual Studio, E-Git, GitHub for desktops, and many others? Because all tools are just wrappers around the commands. If you use the tools you should be fine, but what about when things go wrong? Who will help you then? Knowing the commands makes it EASY to go to using any IDE with Git. Not knowing the commands could be the difference between doing something wrong or just not knowing what to do at all.
Here are some of the commands we’ll be interacting with during this course [and you’ll get good at using them — however — we won’t MASTER any of them, but –after this course — you’ll be able to take the study deeper on your own from here for any of these commands!].
- git add
- git commit
- git push
- git pull
- git fetch
- git status
- git log
- git show
- git checkout
- git diff
- git difftool
- git merge
- git mergetool
- git config
Additionally, this course will show you how to setup a default tool for editing, git difftool, and git mergetool [VSCode in this course, but you could use Perforce P4Merge or another tool if you want].
Introduction: Getting Started
I'm excited that you are interested in learning more about GIT. To make sure this course is the course you are looking for, I want to just go over a few things about what we'll cover in our course.
First, however, I'd like to personally welcome you to this awesome journey you are about to go on. GIT is such a powerful (and popular) source control tool. Distributed source control has a lot of benefits that are unable to be offered by a traditional centralized source control system, and GIT is probably the leader in this area (since it's not the only distributed source control system, I can't officially claim it is the leader ;)). One of the greatest benefits is the fact that creating branches is very inexpensive, and can allow for great flexibility when working with your code (or any files you have in a GIT repository).
So how do you know if this course is for you? The best way to determine is to talk about what this course will offer you: a chance to go from a beginner to an intermediate level with GIT. Here at Udemy, I have a free course that is a five-day challenge for GIT. That is the basic beginner flow, and is a way you could get your feet wet. If you've already done that, great! If you haven't done it but don't need the basic level: also great!
In order to get to the next level with GIT, this course will help you learn how to work with the BASH terminal to run the actual GIT commands to do the following:
- Create a branch locally
- Push a branch to a remote repository at GitHub
- Checkout branches
- Delete branches
- Merge changes from one branch to another
- Merge changes at GitHub using a pull request
- Create and work with a team
- Resolve merge conflicts
- Set a default editor (VSCode - or your choice)
- Set a default difftool (VSCode - or your choice)
- Set a default mergetool (VSCode - or your choice)
- and more
We'll take a direct look at and use the following commands in our course
- git add
- git commit
- git push
- git fetch
- git pull
- git merge
- git branch
- git checkout
- git status
- git log
- git show
- git diff
Additionally, we'll have heavy interaction at GitHub and learn about what it takes to perform common team activities, as well as how we can create branches and merge pull requests at GitHub.
Finally, by the end of the course, you'll be in a position to call yourself proficient with GIT, as long as you understand that this course will NOT take you all the way to becoming a GIT master.
I'm looking forward to working with you and can't wait to hear about your journey along the way.
Let's get started!
I like to start every course with a "What this course won't do" because I feel this information is just as important, if not more important for your decision to take this course as a "what this course 'will' do" is.
So, here are few things that this course will not do:
- This course will not make you a better programmer
- This course will not teach programming at all
- This course will not make you a GIT Master or GIT Expert
- This course will not teach you about advanced GIT commands that rewrite history, or other advanced commands
- This course will not teach you how to rescue your repository when stuff goes horribly wrong
- This course will not help you get a job directly [but if you do get a job, you better know what's in this course, so there is that]
The main idea of this course is to get you to a point where you are comfortable working with branches and merging changes across branches to work as a proficient team member using GIT and interacting with GitHub.
Additionally, I hope that taking this ground-up approach will position you for greater success and understanding, while overcoming fear.
Now that you know what this course will and won't do, let's get started!
In order to work with a remote repository, we need somewhere to host it. GitHub is the ideal choice for this course because it is one of the most popular places to store code, both privately and publicly. There are other choices available for sure, such as BitBucket and Visual Studio Team Services. If you're familiar with using one of those, then by all means keep using it! Most of, if not everything we do in this course will work on any of the popular platforms.
In this video, we walk through setting up an account at GitHub. In some ways I feel silly even putting a video like this out there. Hopefully getting an account at a website is not something you will struggle with. So if you've already got an account at GitHub and/or you know how to do this, you wouldn't really need to watch this video.
In other ways, there are people who like to see everything from the ground up. For those of you who are like me, this walk through will be nice background noise while you work through getting setup at GitHub.
In the end, to move forward with this course, the main goal here is that you have a working account at GitHub where you can create Remote repositories.
One final note: In this video I mention getting an account at BitBucket as something else we might do in this course. To be clear, this course will not have any videos or information about using BitBucket. However, you are perfectly able to use BitBucket if you choose as everything we do here can be done against BitBucket.
In this video, we take a look at getting our first repository setup at GitHub. If this is not new to you, then you may feel free to just skip over this lecture. If you've never done this before, then I hope you will find the information in this video useful.
When working with our files/code we need to have a remote repository so that the data is not just stored on our machine. Could we get by without a central location? Of course, but only if we are the only one using the files, and we'd be losing out on a lot of useful things that a remote repository offers. For example, putting our code on a remote repository gives us the chance to restore to any machine, at any time. Not only that, be we can easily make changes on one or more machines at different times or the same time, and then we can make sure that no changes are lost using branching and merging.
The REMOTE repository will be the centralized location, and we'll clone and/or create repositories to work with on our LOCAL machines. We'll set up our LOCAL repositories so that they track to REMOTE. This is how we'll be able to move changes from REMOTE to LOCAL and LOCAL to REMOTE.
For our course, we'll need a central repository stored at GitHub, and this video shows how we go about getting it setup. If you can't quite follow along the first time, don't worry: The activity that follows will get us setup for our course.
In this video, we go about getting GIT setup on our machines. This is the "Windows" version. Without getting GIT on our machine, we won't be able to run the commands and work with the repositories as shown in the rest of the course.
As an update for this, when setting up for a windows machine - if you are only working on windows and all your team is on windows, you probably should just select to use windows style endings for both checkout and checkin, rather than check in as unix. If you check in as unix and someone on your team is not setup to convert them back, you might run into a file corruption problem.
In this video, we go about getting GIT setup on our machines. This is the "Ubuntu Linux" version. Without getting GIT on our machine, we won't be able to run the commands and work with the repositories as shown in the rest of the course.
Without getting GIT on our machine, we won't be able to run the commands and work with the repositories as shown in the rest of the course. Unfortunately, at the moment I have no access to a MAC to create the installation video. Please use the provided link in the article to go to the official download page, and follow any instructions/prompts to get GIT on your MAC setup.
We'll be doing a lot of work from the command line for our course. The tools that come along with GIT are able to do whatever we need to do, but they are not the most intuitive tools to use - especially for non Unix users.
Fortunately, there are options available and GIT is very extensible - meaning that we can choose to to a bit of customization and be able to work with a tool that is more convenient for us.
While there are many solutions available, the solution I've chosen to use is VSCode for our course. This is a platform agnostic tool, and it is very powerful, and, best of all, it is completely free.
If, for some reason, you don't want to use VSCode, you are welcome to use another tool. You will be on your own for getting it configured, however.
In this video, we walk through getting VSCode installed on our machines.
Although GIT BASH comes with VIM built-in, hitting "i" to insert and "escape colon w q" to write and quit gets pretty old, pretty fast, especially for a non-unix guy like me.
Therefore, we're going to use VSCode as an additional tool to help us when working with GIT on our machines. This is a powerful and free tool, and is only one option of many that are available to you. If you can't stand Microsoft or want to go a different route, you are welcome to do so, but just know that you are on your own for getting the exact syntax for setting up a tool other than VSCode (stack overflow would most likely have the answers you need to use your favorite tool).
In this video, we create the global settings necessary to set our default editor.
Perhaps you already have some projects and you want to get them into source control. If that is the case, then you will want to see how this is done.
After this video, there is an activity that lets you take the default web that I'm using in this course and put it out on your own repository at GitHub.
Additionally, you could just go to my repository directly [https://github.com/majorguidancesolutions/defaultweb_activity] and either
- download the code directly
- or clone the repository locally, then delete the .git folder and start from scratch
- or fork the repository to your own account at GitHub
To be honest, you really don't need any of this. Also, if you have your own code, you can just use that. What we need to get through this course is nothing more than a repository where we can store any text file and just work against it. So if you want to just have one text file in a folder and create a repository and push it out to GitHub, you would be able to do everything we're doing in this course with that minimal implementation.
In the video I mention that I would ask you to clone/fork the repo in a later video. I'm actually not going to do that - it's up to you what you want to do and you can use this repo or one of your own, it's completely up to you.
Basic Git Flow [No Branching and only one Developer]
In the upcoming videos, I'm using a different repository that has a lot of commits and more information than what we've seen so far. If you want that version of the repository, feel free to fork it, clone it, and/or download it to work with it as you wish. Here are other repos where I've done git demonstrations for this course and others [with the bulk of the videos coming from the "Working Directory" where I practice and do multiple demos outside of the videos you'll see in our course]:
Note that you do not need to do anything at all with those: Everything we're doing in this course you can do on the repo we've already created, or even on your own repo, it really doesn't matter.
In some videos, I'll also be going to a website to use as a demonstration tool. That website is Explain Git With D3
Additionally, the tool that I'm using in the videos is called "GitViz" and is available at GitHub. Git Viz by Readify
Finally, in the upcoming videos, I had not yet set any default editor or diff tool. I decided to move that up in this course to save the headaches of working with VIM. So you'll get to see my pain of using the built-in defaults in the upcoming videos.
Even without branching and merging, there are a few things we need to do in order to work with GIT. In this video, and the next few videos that follow, we're going to just go through the process of making a change, adding, committing, and pushing to remote.
If you've never seen this before, this is a bit more than a review, and that's ok. However, you really should have a good command of this before you start working with branches and merging. Therefore, if this is new or confusing to you, I highly recommend that you practice this section a few times to get the flow down.
In this video, we're going to make a couple of quick changes and then "stage" them to INDEX with the [git add] command.
There are many ways to use add, but the two most popular that we'll rely on are:
- git add <specific-file-name>
- git add .
Using the period [dot] after git add essentially picks up everything that is modified and tracked and adds to the INDEX (stages) for a future commit.
Another note about the video:
You'll notice that I had to edit these files inside of VIM. At the time I recorded this video, I had not yet setup the default editor to use VSCode. Since we have already set that up in our course, you should be able to avoid using VIM, but you are welcome to do so if you wish.
After adding our changes to INDEX (staging the changes), we can create a commit. A commit is a recorded snapshot of the working directory, and is directly accessible using the commit ID. Once we create a commit, we have a record in our history of the exact state of the files as they were at the time of the commit.
A couple of important things to remember:
- If we make changes, but don't stage them, then the commit will ignore those changes.
- If we stage changes in a file, then make more changes to that file without staging them, only the staged changes are committed
- We cannot add and commit untracked files at the same time. Using the combined -am flag on commit will only add files that are already tracked.
Now that we have created a commit that recorded some changes into history, we need to get those changes out to the remote repository. In order to do this, we have to "push" the changes.
In this review, we work directly against master. This is actually pretty dangerous and we'll learn better ways to do this in the later part of the course. If you are working on a public repository that has many users, you should most likely not use this strategy. I'm not saying it's impossible, but I am saying it could be very dangerous.
In any event, we need to understand that to get our changes from LOCAL to REMOTE, we do need to push the changes to some branch on our REMOTE, and since we may not know how to branch yet, this demo uses the only branch we have -> master.
Anytime we are going to start working on a branch, we should remember that we want to "sync up" or "get the latest changes." This is important because it allows us to have a starting point that is as far forward in history as possible, and helps to reduce/minimize the number of conflicts we might encounter later.
To get the latest changes, there are three commands we'll become very familiar with running, in sequence:
- git checkout master
- git fetch origin
- git pull origin master
Another note: If for some reason the repository you are working with does not have a readme file. You could just add one or you can make a simple change on any file that you have in the repository. It really doesn't have to be exactly what I'm doing here in order for you to get the same results when using the pull command on your local version of the repository.
We'll hit a few commands along the way that just help us when working with GIT. Two of those commands are [git log] and [git show].
These commands will give us tools that let us view the history of changes by commit id for the specific branch that we are currently on [git log]. Additionally, using the [git show] command against a specific commit id will give us exact details about the commit as it was written.
Keep a few things in mind. My commit ids will never match yours. Your repository might have some or all of the files that mine has, and some may not be there depending on what you are doing compared to what I'm doing. Also, you may not have nearly as many commits as I do at this point. This is all ok. What matters is that if you do these activities, you are seeing your commits and your files, and you can work against your commits as you go. So, just to be clear, you should not expect to be able to type the exact same commands as me, unless you have my repo which contains those commits in it.
Tools to improve our command line experience for difftool and mergetool
When looking at the differences in commits for GIT, we can easily do this by running the command
[git diff <commit1> <commit2>]
[git diff --cached]
However, using the default diff view and seeing our changes print out in the command terminal is not really an ideal way to review the changes and see the exact differences.
Even though we won't be diving into the diff command or using the difftool much going forward in this course, we're setting everything else up, so we may as well get the difftool setup as well. If you want to go back to the previous section and go through the commit video again, you'll see the difference if you use difftool instead of diff on the commits.
This videos shows how to configure the global config for a default difftool set to Visual Studio Code
In addition to using VSCode for the default difftool, I wanted to show how you can turn the difftool prompt off. If there are a ton of files to go through when reviewing differences, having to select "Y" for reviewing for each one could be rather annoying. Therefore, we can shut off the difftool prompt so that it won't ask for each file with differences.
We'll definitely be taking a look at merging in this course, and towards the end we'll hit a couple of merge conflicts. For that reason, and in order to avoid going back to 1985 with the built-in merge tool, we're going to set the default mergetool to VSCode. This will save you a lot of pain when it comes time to do a merge conflict resolution!
Branching: Working as a single-user with Local and Remote branches
Our first major topic for this course is branching. In this video, we take a look at what it means to create a branch and how we can start working with branches to avoid working directly against master.
Using the [git branch] command, with a branchname [git branch Feature01], we see how easy it is to create a branch. However, we also realize that just creating the branch doesn't actually take us to the branch to do the work. In order to move from one branch to another, we need to use the command [git checkout <branchname>] to actually move to that branch.
One of the most important things to remember is just creating a branch doesn't take you to it, so be careful when you start making changes to remember to check that you are on the branch you think you should be on.
Whenever we start a new workflow, it's a good idea to make sure our local branch is up-to-date with our remote tracking branch. For this video, I show how to use git pull to get the changes from the remote repository to the local repository.
Running the [git pull origin master] command will not hurt anything if no changes are present, and will update our local repository to contain all of the latest changes that are in master at the time of the pull. However, there will be times that even though you do this, someone else on your team will update master before you get a chance to merge your feature branch. This is ok, and this is how GIT will become very powerful for us in the future. Therefore, we'll talk about situations like that later in the course.
Now that our master branch is up-to-date, it's time to start working with a new branch. In this video, we learn about creating a new branch in a couple of different ways.
First, we can easily create a new branch with the command
git branch some-branch-name-here
However, when doing that, we only create the branch, and we don't actually move to it. Therefore, most of the time when we are creating a new branch we'll actually create it and also move to it in one command:
git checkout -b some-branch-name-here
By the end of the video, we should have a pretty good idea of what it takes to create a new branch and move to it in our LOCAL repository.
For the most part, when creating branches going forward, we'll mostly use the "checkout -b" version of the command, as it will both create and switch to the new branch.
I encourage you to work along with me as the video plays, but don't worry, there is an activity coming soon that will give you a chance to work with branches on your own.
Now that we're on a feature branch, we can freely make changes and commit them. What's great is that those changes become unique to the branch, and we are not locked into them until we merge them into our master branch.
For this video, we'll go through a few operations where we create a couple of feature branches and make different changes and commit on the branches, and see how these commits and changes are definitely locked to the branch we created them in.
Some of the main things to remember are:
- When creating a feature branch, my parent is the branch I'm currently on. Therefore, most of the time I probably want to branch off of master, or at least some main feature that is directly branched from master
- If we make a change and don't commit the change and move branches, the change comes along with us and can be committed to the branch we've switched to. This is highly useful if we are trying something on a feature branch and hit a dead-end but don't want to lose it. We could checkout a new branch, commit and then switch back to the feature branch. Our change would live in the other branch but no longer be on our current branch.
Intro to Merging [complete the branching section first!]
In this video, we learn about merging in GIT.
This is an overview of what it looks like when we actually go about making the merge happen. As a note, we're on the happy path here, and aren't going to be dealing with any conflicts, as we're the only developer to this point.
It's important to remember that in order to merge correctly, we need to have a common parent commit in our history.
And it's also important to remember that we need to be on the branch we want to merge changes into, not the branch we want to merge from. In the video, we see what happens when we merge the wrong way, merging from the branch we want to merge from instead of on the branch we want to merge into. We then show what it looks like when we get things merged correctly. The good news is we can still correct the situation with just another merge (as we see towards the end of the video).
Also remember that doing a merge creates a new commit, so the branch we merged into the current branch is left behind by one commit. Even though they would have the same codebase, the extra commit is a result of the actual merge operation, which is a marker in our history.
As we now have changes on our local branches, we want to merge the changes in order to get them into our master branch. We're actually going to do this locally first, and then push up to master at GitHub. Later we'll learn a better strategy for protecting our master branch and for working with a team. However, for now, as an individual, this will work just fine, and gives us a chance to really learn about how this pushing and merging works without muddying the waters too much.
As mentioned, if you are working in a team environment, this is not the best/safest way to go about this, so I want to put that out there in case you are trying to do something against production today in your work environment. Instead, it would be better to work with the team flow that we'll learn about later in the course, where we push to GitHub and then merge with a pull request.
For now, however, since we're just getting started, and since we're probably the only one working on the codebase, there is very little risk of this causing an issue for us.
In the video, we remember that it is important to checkout the branch we want to merge into, and we merge from the branch we want to get into our current branch. Since we're merging directly to master, we will checkout master, and then merge the Feature01 branch into our codebase. We'll then merge the Feature03 branch into master as well, so both of our branch changes will be in master.
Once again, we're on a real happy path here as we've completely avoided causing any merge conflicts - for now.
We get to see both a fast-forward merge and a merge using the recursive strategy. Since we get multiple merges, master ends up being ahead on the commit for merging, so we then switch to Feature01 and merge master to get it up-to-date.
We finish up by pushing master out to GitHub so that we will have all of the changes that were merged locally into master directly committed to master at REMOTE.
Branching and Merging With Pull Requests [Complete sections 4 and 5 first!]
Having just completed the first merge operation in the previous section, we are in a good place to work as an individual developer with branching and merging. However, we really need to learn a way that is safer than updating our remote master from our local master branch. If we were to corrupt our local master, we could easily just re-clone the repository and we would be ok. However, if we corrupt master at REMOTE, we break it for everyone.
In order to protect our master, a better strategy is to push our feature branch out to the remote, and then do a merge at GitHub. Technically, we're doing the same thing -> merging a branch into master. However, using a pull request, we can make sure that other team members have a chance to review our changes, as well as have a chance to reject the merge. Additionally, if everyone is using pull requests, it's much easier to manage potential conflicts, rather than everyone just pushing directly to master and hoping to be the first one there.
To get an unpublished branch out to GitHub, we want to use the [git push -u origin <branchname>] syntax.
We've seen what it takes to create a branch locally using commands, but what if we just want to create a branch at GitHub and work with that branch in our local repository? Of course this is possible, and is an easy way to work with branches and assure that the branch is already tracked at GitHub (can then push without the -u flag as it won't be unpublished or untracked).
In the video, we find the place at GitHub where we create a branch and go ahead and create it. Once we have the branch, we'll need to get it locally so that we can start working with it. We'll see how to do that in the next video.
In this video, we get the remote branch we just created in the previous video down to our local repository.
When we move to our local, we can see all of the branches we have, as well as the references to remote branches using the command [git branch -a]. In the video, I show the command without the -a, which only shows the local branches that I have.
We then move into using the [git fetch] command, which updates our local references. This gets us a reference to the new branch created at GitHub, but we don't actually have the branch locally either. So how do we get the new branch? We can just check it out! Since we have the reference already, if we checkout a branch with the same exact name, GIT will automatically create a local version for us to work with!
Once we have the branch checked out, we're ready to start making changes on the local repository, which will position us to then do a commit and push, followed by a pull request to merge at GitHub.
This video is just a quick review because we need to do the general workflow of making a simple change, adding it to index, and then committing our changes into our local repository.
Since the changes are on our feature branch, we know we need to merge it somewhere. In our 'new' flow, we are no longer going to merge to master, so we need to push the branch directly to GitHub. We'll do that in the next video.
In the previous videos we got a new branch from GitHub, made some changes, and added and committed the changes. Now we need to move the changes to our feature branch at the remote repository.
Since we originally created the branch at GitHub, fetched it and then checked it out, the branch was already setup to track to the feature branch at GitHub. For that reason, we can easily push without the -u flag [git push origin <branch>]. This also lets us know that anytime we have already published a branch, the -u flag is no longer needed.
Once we get the changes pushed out, we are ready to learn about how to work with pull requests at GitHub.
We've created a branch at GitHub, fetched it, checked it out, made changes, committed, and pushed the changes out to GitHub. Our strategy now is to protect master, so we did not merge to master at our local repository, and we pushed our feature branch directly.
To get the changes into master now, we are going to rely on the pull request feature at GitHub. This is an awesome feature that allows for easily sharing your potential changes with team members, as well as reviewing the code one final time before actually merging to master.
GitHub lets us know right away if we can merge the pull request with a green checkmark and message. If there is a conflict, GitHub will give us a warning, letting us know we can't just merge the changes without first resolving the conflict.
The Pull Request feature also gives the reviewer a chance to enter comments directly on the code, request a review, reject a change, and assign team members. This is an awesome way to keep track of changes that are needed to make it so the code request is worth of being approved.
We've still stayed on just the happy path, so our code doesn't yet create any conflicts. Once again I want to make sure we get these processes down little-by-little, so that when the stuff that is a bit more frightening happens, we are ready for it, and confident enough to move forward.
In the video, we setup the pull request and talk about the features at GitHub and ways we could interact with the pull request. We'll have the pull request ready, and we will go ahead and review and merge the request in the next video.
In the previous videos, we created a branch at GitHub, pulled it down, made changes and commited, pushed up to GitHub, and then opened a pull request. In this video we complete the merge operation via the pull request.
The nice thing about using the pull request at GitHub is that we get the built-in tools for code review that team members can interact with changes as requested by other team members. With this, comments can be made, and emails will be automatically sent to the affected team members.
IMPORTANT: Before you merge, make sure that the pull request is telling us exactly the branch we expect to be merging into from the branch from which we are merging. This is critical as you don't want to accidentally merge into master if you weren't intending to do so.
Once we're ready, we hit the "Conversations" tab of the pull request. We can then choose how to merge the pull request. We're just going to do a basic merge and commit (which does generate a new commit id into history).
With that, we go ahead and confirm and put any messages in place we would like to.
We finish up by noting that the merge actually creates a commit in history. This means our local master branch is now behind the remote master, so we'll need to update our local repository to make sure we are up to date.
Now that we've made all the changes we wanted to make, and we have merged into master at GitHub, we need to get things up to date on our local repository, especially if we are going to keep making changes on the feature branch.
Currently, our local repository does not know that it is behind, so we need to help it find that out. We'll then pull the changes locally so that we can continue developing on our local branch.
First, we should get local master up to date, then we need to merge master from origin into our local branch. This will get everything up to date.
First we want to fetch to get our references up to date, which will let us know that our local master is behind our remote master, so we run the [git fetch origin] command. We then checkout master [git checkout master] and see that we are behind.
There are a couple of camps here. Do we pull or do we pull with rebase? Ultimately, that will depend on your team and if you are crazy about having a linear commit history, or if you just want to work with Git and don't care if the branching is all over the place. One thing to note is that it is less important to pull with rebase for master than for a feature branch, as master is generally written in stone and pulling with rebase just pulls master the same as using a regular pull would.
We'll go forward without rebasing, which is a bit more advanced than we are going to go in this course. We'll so a straight [git pull origin master], which then gets our local master up to date.
To merge into our feature branch, we then checkout our local branch, and do a merge from master into our local. This gets our local version of the branch even with master and ready to go for continued changes. You could do a push to get origin even as well, but all you're doing is pushing a merge commit - which you can do later when your changes are done as well. It's up to you if there is a good reason to push the merge commit immediately. To get even, we just push again with [git push origin].
We've now seen an entire workflow where we used a branch that was created [either locally or at github], made some changes, commited them, pushed the changes [either with or without the -u flag, depending on whether or not the branch is published/tracked]. We then created the pull request, so master was protected and ultimately gave us a safe way to merge to master. After merging, we then used fetch and pull to get our local repository up to date, checked out the feature branch and merged master to the feature branch, and then pushed the change back so that everything would show up as even.
In this video, we start doing a bit of cleanup, and see what it takes to delete a local branch. If you worked through the branching activity previously in the course, this will not be new to you. If you didn't work through that activity, make sure that you take a look at this, because we need to overcome the fear of deleting, and we need to be able to clean up our repository. Having too many branches hanging around just starts to get messy.
To delete a branch that is fully merged, we run the command [git branch -d <branchname>]
If we're going to delete a branch at GitHub, we'll probably just go out to GitHub and delete it. That being said, it's entirely possible to delete remote objects from our local terminal. In this video, we show how to delete a branch from the remote repository using just the BASH terminal.
During the video, I said I couldn't push from the branch that I'm on. That's not right. However, I can't a branch if I have it checked out, and since I was going to ultimately delete it, that's why I needed to switch.
The really important thing that we learn during this video is that our local and our remote are both independent of one another. Therefore if someone deletes your branch at GitHub, you can still republish it. Also, if for some reason your local repo gets corrupted, you can just pull the branch from GitHub again, as long as it is still there.
If you did the branching activity earlier in the course, then you've already seen how to do a 'force' delete of a branch that is not fully merged - or is appearing to GIT as not fully merged [it might happen if commit history has been rewritten with a squash or a rebase].
The important thing to remember is that even when a branch sometimes appears as "Not fully merged" it may be - depending on what has happened with the history. If you know for sure that everything you need from the branch is in master and you want to delete the branch, the -D flag will force the delete.
What's also important to remember is that GIT has the ability to check history and see if all commits appear to be in history. This gives us more confidence that running the -d flag on delete is fairly safe - after all, if you have outstanding commits, GIT will warn you and force you to make certain you want to delete the branch.
In this video, we do a couple of quick changes to simulate a branch that is unmerged, so that we have a reason to use the -D flag, since the branch will not be fully merged into master at the time of delete.
In this video, we're going to wrap everything up and put it all together. For example, we'll do a couple of quick pushes and pull requests, and delete the branches both at GitHub and Local.
The reason we want to do this is because our repo is getting pretty messy. We'd like to make sure that all of our changes are in place that we want to keep, and we want to delete any branches that are fully merged and/or stale.
We'll review making the pull request and checking out what will be modified if the PR is merged, and then merge it. Once the PR is merged, we'll delete the branch directly at GitHub. Of course that means we need to also delete it at local in order to keep things cleaned up fully.
Once we get everything deleted at GitHub, we need to clean up at local. What we'll notice that that all of the local branches remain, even if they had been deleted at GitHub. We also note that locally, we have references to the remote branches, even after they are deleted. Therefore, we'll still need another way to get rid of those references that are no longer valid at REMOTE, and we'll see how to do that, as well as finish the cleanup in the next video.
In this video, we continue our cleanup operations. In the last video we pushed and merged all of our valid changes at GitHub, and then deleted the branches from GitHub that we no longer need.
The first thing we are going to do in this video is get rid of the remote references that no longer exist at GitHub. The remote references are all labeled with the origin keyword -> like "origin/somebranch". We know that when we delete a branch at GitHub, such as Feature02, we can still have a local branch "Feature02" and a remote ref "origin/Feature02". What's great is that using a simple prune on fetch, we can clear out all of the origin refs that are no longer valid. With one call, all of the remote references are gone, AND our local branch remains. This means that running the prune operation is COMPLETELY SAFE. Additionally, if a branch exists at GitHub and you are afraid that would be deleted, you can be assured that it will not be (we show this in the video as well).
I wish that in the video I had shown [git branch -a] instead of just relying on the GitVis. If you don't have GitVis, you can use that -a to see all the local and remote branch references.
In this video, we also are introduced to the --dry-run option flag. This is an awesome flag because it gives us an overview or a peek at what would happen if we had actually executed the command.
While we are working through the cleanup, this video also gives us a look at the inner folders of the .git folder, and shows how each of the references actually has a marker file in the appropriate subfolder. While we could just wipe out our references there if we want, that's really not safe and is generally a bad idea. It is much more appropriate to use the commands within GIT that we are becoming masters at using.
We finish up the video by evening out our local master with origin/master, which also shows that we didn't lose other branches that exist at GitHub.
Finally, in the video, we run the command
[git remote prune origin]
But we could have accomplished the same thing with the command
[git fetch origin --prune]
Intermediate Git Operations: A simple multi-developer flow with merge conflicts
In this video we are just going to setup an organization so that we can create a team with another GitHub account. This is a little bit more than you will need to do in order to understand the flow of the team activities, but I wanted to show this anyway.
Because I have multiple accounts at GitHub, I can then simulate multiple developers on a team. If you want to do branching and merging as a team without an organization, you can simulate this just by having different "developer" branches. We can easily crate conflicts and work against the same repo with different branches to simulate what it would be like if multiple people were working against the same master branch.
One of the nice things about having a "team" is we can actually assign users to review a pull request, and get our own selves added to the pull request as an interested party. Doing this sends emails anytime the status of the pull request is changed and/or we make any comments or approve or deny a PR.
Again, you don't need to do this, and in the final activities we won't be using it, but it's important to see that GitHub can do a lot more than just be a central place for your repository to be stored.
In this video we just setup the team with both members as owners.
I then create a "Primary" team, but you can see how we would be able to put together teams of developers and group specific people. This would be awesome because a user could tag the whole group or include the whole group on a pull request or communication.
We also take a look at how we might be able to setup a Kanban board to keep track of progress within a project.
We'll also look at making a repository for the team, and see what it takes to transfer ownership of a repository from a member to the team (in case this is something you want to do someday)
And then we'll create a new repository "ultimate-default-web" for our team to interact with. We'll setup this repo in the next video.
In this video, we see how easy it is to take an existing directory that contains a repository, delete the repository, and push to a new remote repository after creating a new empty git repo on the local. Just don't forget to do the intial commit before pushing, or you'll get the error "src refspec master does not match any"... and that could be scary.
Without an initial commit, the repo can't be pushed up to the remote. So we then perform the initial commit. Since I took this repo from another, on my initial commit I stamp the commit message with the latest commit of the repo it came from.
Once we get the repository pushed, we're ready to start simulating a team working against this project.
From here on, the "code" changes we make are in the ultimate web. You could just keep going on any repository, however, you do not need to do this against a new repository. The things we are doing are not rocket science in the world of development. The main point of what we are doing is trying to learn how the GIT flow works, and how it would work with different developers.
If you want to use the ultimate default web, you could just fork it from my repo, or you could download it, and go through setting up the repo. But with all of that, again, we are just doing very simple stuff, so really keeping going on the current repo you are on is just as good (unless you want more practice), and could be easier for you in the long run.
In this video, we are really just reviewing stuff that we did as a single developer with branches. So, if you haven't watched that section, you'll probably want to do that now, as we'll move through the stuff we've already seen fairly quickly.
When this is all said and done, you should have a working branch for developer 1 created at GitHub in the repository you are working against. [Also, while I do encourage you to work along with me, the activity at the end of the section will give you a good practice with this as well].
In this video, we review the ways that we work with the local to get things up to date and even with remote. The main commands we interact with each time we start a new developer process are:
- git fetch origin || git fetch origin --prune
- git pull origin master
- git checkout <branchname>
- git branch || git branch -a
By the end of the video, we'll have the latest version of the repo synced up with our master [no changes yet anyway] and we'll also have our local branch ready to go for the 'developer 1' changes.
In this video, we review what it takes to make some changes, add, commit, and push to remote.
We don't have to do these videos in a specific order, and if you wanted to play with the flow, you could do the changes but not push yet. It's up to you how much you want to practice and see how things work if developer one pushes first or second, or if one or the other gets their changes committed into master even before the second developer starts working.
We've seen how to do this a few times now, so we move fast through this video. If you are struggling with these concepts, you will probably want to go back to the first part of the course and review once again.
To save time, here we'll just log in as the other team member and do some changes directly at GitHub.
If this was the real world, developer 2 would create their branch (either at remote or local), make their changes on the local machine, and then push their branch to GitHub. They would then create the pull request, and ask for it to be reviewed.
On the merge of the pull request, the other developer or a manager would be able to then merge the pull request, even if they know it will create a conflict with their work.
As you might have noticed, we're abandoning the happy path now! This means we know for sure that we are going to have a commit conflict (which we're creating on purpose to show conflict resolution later).
At the end of the video, developer 1 merges the pull request, even though they know that the changes are going to conflict with their changes.
As developer one, it's time for me to merge my feature changes. I happen to know that there is a conflict at the REMOTE, so I have to get all of that ready to go.
In the real world, we may or may not know about the conflict, so we'd push our changes and create the pull request to see if we can simply merge. In the video, I skip creating the pull request here (but you can see what it looks like in the activity at the end of the section). In the real world, you'd create the pull request because there may not be a conflict so there would be no need to sync up and resolve.
Either way, assuming there is a conflict like what we have here, the next steps are to bring the changes down to local and resolve at local (even though we could try to resolve at GitHub).
So on our local, we switch to master, and pull the most recent changes down to our local repository to get developer two's changes. I then need to merge the latest master into my feature branch and resolve the commit conflicts.
Note: In this video, I had NOT YET setup VSCode as my mergetool, So I had to fight through the merge in the style of 1985. Luckily it was not a terribly difficult change, but hopefully this illustrates how important it is to setup a better merge tool. I was able to get lucky with the file having all of the changes already and just saved and committed. In the activity, I use VSCode as the mergetool, which is much more intuitive and works much better as a merge tool.
I committed the merge with a git commit, but I could have also have done [git merge --continue]. Also, if the merge goes terribly wrong, then we could get out with the [git merge --abort].
In the end, I have the merge conflict resolved one way or another, and committed, so I'm ready to push my local changes to remote so that they can be merged without conflict.
In this video, we push our changes that have been resolved locally into our remote branch.
Because the conflict has been resolved, we can create the pull request and it will be able to be resolved. If we had not resolved the conflict, we would get a red notification that lets us know there is a conflict and the changes can't be merged. We'd still be able to create the pull request, but we'd have to resolve the conflict in one way or another before GitHub would let us merge the pull request.
Our PR is able to be merged, so we asked the other developer for a code review and that developer goes out and reviews and then merges the pull request.
We can then see that all of the commits are in the history at REMOTE, and, of course, if we wanted to continue locally the first thing we should do is get our branch(es) even with the latest version of the code.
- git fetch origin || git fetch origin --prune
- git pull origin master
- git pull origin <feature branch>
- git checkout <feature branch>
- git merge master
In this video we are going to run through another conflict and team merging resolution. Since the first merge showed that 1985 version, I then set VSCode as the merge tool on one machine and p4merge as the mergetool on another machine (I moved the VSCode as a mergtool video up to the top of the course from here so you've already done that activity).
Since I also had setup p4Merge setup, I gave a quick look at the settings that I had working with p4Merge before I switched to VSCode. I only wanted to show that so that anyone who went that route could see what those settings looked like.
So we move quickly here, creating a local feature branch, making some simple changes, and push them out to the REMOTE by publishing our branch. This gives us more practice with starting from a local branch, rather than starting from a branch at GitHub.
Once the commit is published, we then go out and create the pull request and assign the other developer to review it.
In the meantime, on the other machine, the developer is creating another feature change, which will once again create a new conflict. This developer had moved their feature branch forward and decided to keep working on that branch, rather than creating a new one. This is something that could easily happen in the real world as well.
By the end of the video, dev 2 has created the pull request, and dev 1 has changes but they will be in conflict, so that will need to be handled.
In this video, we are just going to get setup to resolve the merge conflict.
So quickly here, we will just get everything synced up from the most recent master changes that were already done by another developer. Since we didn't have those and there is a conflict, we are going to have to resolve it, which we'll do in the next video.
In this video, we get to see how much nicer it is to use VSCode for a mergetool than the view we got to see earlier on a merge conflict. As we can see, VSCode has some really nice options for merging.
In the end, it will be your job as the developer to make sure that you get the changes into the commit as they need to be in order that both of the developers will have their features correctly implemented.
Once we select 'Accept Both Changes' or another option, then we can commit or continue the merge, and then push to REMOTE. This will set us up to create and merge a new pull request, and we know that there will no longer be a need to worry about a conflict, because we have already resolved it.
It is not a good idea to resolve merges at GitHub. That being said, you can do it if you really want to.
In this video, we get to see what it looks like when a commit is in conflict with another and how we can resolve that conflict directly at GitHub.
Again, we've already seen the better flow many times at this point, however it is possible, so I wanted to show it to you.
I'm super excited that you made it to the end of the course. I hope you have found our time together useful, fun, and informative. I also hope you were able to work through and enjoy the activities at each step of the way.
Now that we are at the end of this course, you have all of the tools you need to be an intermediate GIT user. Hopefully you've overcome some of your fears and also have the ability to work as a team member or at least a single user with branching and merging in GIT.
The really great thing is that we took a pretty deep dive into the commands in this course. In real modern development scenarios, you'll probably use a GUI tool of some sort, perhaps even built into your IDE to interact with GIT. So why did we learn the commands? Because you can easily go from a command line to a GUI and understand exactly what is going on, but when the GUI fails, if you haven't studied the command line, then you will find yourself wanting to know more about how GIT works, and perhaps even overcome with fear at the possibility that your hard work is going to be lost or corrupted.
As we conclude, I hope you will agree that we've seen many aspects of merging and branching, and are well-positioned to succeed with GIT in the future.
I wish you all the best and can't wait to hear from you about your success stories.
Now that you are at an intermediate level with GIT, you should consider moving into the world of Advanced GIT.
There are many commands and interactions with GIT that await you, such as:
- Squash and Merge and/or interactive rebasing
- Working with the reflog
- Setting credentials in config
- Setting up a git ignore file
- Cleaning the repo
- Cherry Picking
- And much more
It is completely possible to be proficient with GIT without fully understanding those commands, and as we've seen in this course, we can mostly work as a productive team member, as long as we are on the happy path and don't hit a scenario that requires rewriting history.
As a proficient developer or user of GIT, however, you can quickly start moving into the realm of expert by learning about the advanced features. You'll also become the person on your team that everyone wants to go to when they don't know how to get things working with their GIT scenario.
All the best to you!
Here is the link for my main website, where you can always find the latest information from me:
My Website: http://www.majorguidancesolutions.com
Here are some links and coupons for other courses I offer at Udemy:
GIT Advanced Commands:
ASP.Net MVC Quick Start:
Introduction to HTML:
Bootstrap UI For Everyone:
Introduction to Unit Testing in Java with J-Unit 4 (included already in the Intro to programming course):
I hope you have found our time together valuable and have enjoyed learning the material!