Git Advanced Commands

Tags: Git

Practical GIT training: cherry pick, rebase, revert, stash, clean, and more. Take your GIT skills to the next level.

Last updated 2022-01-10 | 4.4

- Work with some advanced GIT commands
- Know how to rewrite history with squash
- rebase
- and reset.
- View history in the reflog
- expire unreachable commits using reflog and the garbage collector

What you'll learn

Work with some advanced GIT commands
Know how to rewrite history with squash
rebase
and reset.
View history in the reflog
expire unreachable commits using reflog and the garbage collector
Create linear GIT history trees
Use Aliases
Perform a Cherry Picking operation
Use the stash to temporarily save changes
Work with Tags
Become a more advanced GIT user

* Requirements

* You should be familiar with GIT. You should have GIT installed on your machine
* and an account at GitHub or BitBucket.
* You should know how to work with basic GIT workflows

Description

This course is a deeper dive into GIT.  As such, it is expected that you would have at least some working knowledge of GIT before you take this course.  For example, you should be familiar with basic commands like "add, commit, push, pull, fetch, and merge."    You should also have a basic working knowledge of working with a REMOTE repository like GitHub or BitBucket.  

The first part of this course will just make sure we're setup for the remaining part of the course and serve as a simple review.  This includes basic stuff like getting an account at GitHub, setting up our machine for working with GIT, and setting a few default configurations.  Feel free to skip this part of the course if you are already good to go.

The bulk of the course will then take a deeper dive into the following commands:

  • git commit --amend
  • git reflog
  • git rebase
  • git config --global alias
  • git fetch --prune
  • git reset [both soft and hard resets]
  • git clean
  • git revert
  • git cherry-pick
  • git stash
  • git tag

Additionally, we'll see what it looks like to perform different merges at GitHub to complete a pull request, including

  • Squash and Merge
  • Rebase

At the completion of this course, you'll be proficient with some of the more advanced GIT commands that we encounter when working with GIT repositories on a daily basis in the real world.  You'll also have been exposed enough and understand enough about the commands to take your skills to the next level when working with GIT.  You'll also know what it takes to make and keep your tree linear in your GIT history, and you'll have tools to rescue your repository when things get a bit tricky.

Who this course is for:

  • Beginner to Intermediate GIT users
  • Developers
  • Anyone who wants to learn about some of the more advanced features of GIT
  • Someone who is looking to be a team lead and needs to improve their GIT skills
  • Anyone that needs to be able to have source control on important files [code, images, documents, spreadsheets, etc]

Course content

4 sections • 56 lectures

Welcome and Info about this course Preview 02:00

Welcome to GIT: Advanced commands!  I'm excited to go on this journey with you!

This course is designed to take you to the next level -> from an intermediate/proficient GIT user to someone who is close to a master of GIT.  I say "close" because at the end of this course you will have been exposed to many of the GIT tools you would need to be in command of as a GIT master, but still just a bit short of actually getting there - as that 'title' really comes more with experience and time - and exposure to more and more tricky situations.

That being said, it is my hope that by the end of this course you would be the person on your team that everyone turns to when there are problems with the repo, or when they need to know how to do something with the command line that just can't be done with a GUI (or at least not easily done).

It is expected that before taking this course you have at least been exposed to GIT, and are familiar with a basic flow for add/commit/push/pull/fetch/merge/branch/and checkout.  We'll see them again in the course from time to time, but we won't cover them, so it will be harder to work with this course if you don't have a good command of them coming in from the start.

We will quickly dive in with a review, and make sure that our machines are configured to do this course with minimal issues.  Feel free to skip any lectures that you are already in command of or just don't need to review - I leave that to your personal discretion.

After getting setup, the bulk of the course will be spent learning about working with some of the advanced commands that GIT exposes for us to do everything from a simple revert of a commit or a reset of changes, to rewriting history with rebase and picking commits out of a tree with the cherry picking operations.

You can review the curriculum to see the commands, but here they are, in the order they will be presented in our course:

  • git commit --amend
  • git reflog
  • squashing and merging at GitHub
  • git config --global alias.x
  • git reset
  • git reset --hard
  • git clean
  • git revert
  • git rebase
  • git cherry-pick
  • git stash
  • git tag

Let's get started!


What this course won't do [Please review before purchasing] Preview 03:16

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 into the all-knowing GIT Diety
  • This course will not spend a lot of time on basic GIT commands
  • This course will not teach you about webhooks or continuous integration
  • 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]
  • This course will not go deep into shell scripting
  • This course will not cover git bisect
  • This course will not cover using email to push/pull changes or patch
  • This course will not cover cherry-pick with patching
  • This course will not cover git blame

Get an Account at GitHub Preview 03:19

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.    

Setup a Repo at GitHub Preview 03:56

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. 

Get an Account at GitHub and Setup a new Repo

As part of the operations we'll be doing, we'll be interacting with a REMOTE repository (GitHub). If you don't like your stuff being public, you can always choose to use BitBucket.

Get GIT on your machine [Windows] Preview 05:11

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.

Get GIT on your machine [Ubuntu Linux] Preview 02:04

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.

Get GIT on your machine [MAC] Preview 02:25

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.

Get GIT on your machine

Make sure you have installed GIT on your computer. We'll need it so the terminal will work to run commands. Some machines may already have it installed [I'm looking at you, Linux user!]

Get VSCode for use as an editor, a diff tool, and a merge tool Preview 03:49

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.  

Get VSCode on your machine

We'll use VS Code as a mergetool, a difftool, and our default editor in the course, so you'll want this to work along. It's free, and works on any machine. It also has some cool extensions available for other things, for example, Prettify JSON and XML, so it's useful even outside of this course.

Setup VSCode as the default editor Preview 05:13

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.

Setting VSCode as the default editor

In this activity, we get VSCode setup as our default editor so we don't have to use VIM anymore [you still can if you want to...]

Setup VSCode as the default difftool Preview 08:25

When looking at the differences in commits for GIT, we can easily do this by running the command

[git diff <commit1> <commit2>]

or

[git diff --cached]

among others.

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 (if at all) in this course, we're setting everything else up, so we may as well get the difftool setup as well.

This videos shows how to configure the global config for a default difftool set to Visual Studio Code

Turning off the difftool prompt Preview 04:42

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.

Setup VSCode as the default DiffTool

Being able to easily see differences between commits is critical in our effort to get better at GIT and see the things we've done. VSCode makes it much easier to see the differences than just trying to read them in a command terminal.

Setup VSCode as the default merge tool Preview 04:05

Whenever we hit a merge conflict, we want to have a nice tool to perform conflict resolution.  If you don't already have something in place on your machine, this video will walk through getting VSCode setup as the default mergetool.  Having set VSCode as your default mergetool will make life a lot easier when merge conflicts arise.

Set VSCode as the Default Merge Tool

Using VSCode for a merge tool is not required but is almost necessary. Seeing the difference makes most everyone want to use some tool for merging, instead of the built-in tools. We'll get VSCode setup so that when we hit a merge conflict later, it is much easier to work with this tool.

I already have a project, how do I add it to a REMOTE repository at GitHub Preview 09:48

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 a zip file for a project called "default web" that has a very simple web solution in it.

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.

Get an existing project into a new LOCAL repository and then publish to a REMOTE

This activity walks us through getting any folder with any project setup as a LOCAL repository, and then what it takes to publish that LOCAL repository out to our REMOTE [GitHub].

Get GitViz [Optional] Preview 08:25

I'm using a tool called "GitViz" to do some demonstrations throughout the course.  I put together a video on how to get it up and running if you want to have it on your machine.  I believe there is a release version in the repo but if you have VS and want to build the latest version, you should be able to do that.

The link to the repo is: https://github.com/Readify/GitViz

The Repo I am using - Note: You can use any repo, you don't need mine. Preview 00:17

Please review the ariticle for this lecture to get more information about the repository that I am using in this course.

The website I use in some of the demos Preview 00:04

Please review the attached article for information related to the website I used in some of the demos.

Amending Commits: Changing the commit message Preview 06:00

In this video, we take our first look at the ability to amend a commit.  This is accomplished with the command [git commit --amend]  and then an appropriate message either with the -m flag or through the editor.

We'll take a quick look at viewing our history with the git log and show how we can use the amend feature to change the details of the last commit.  The important thing to remember is that the original commit is orphaned and a new commit is created with the new details, essentially 'replacing' the old commit.  The reason this is important is because anytime we change our history like this, we need to be certain that we are not modifying a public commit change.  

For example, if we were working against master and changed the commit history with an amend (or rebase, reset, or another history-altering operation), we would be putting others at risk.  If we take away commit a1b2c3 and developer 2 is reliant on a1b2c3 to be in the commit history as a parent to their changes or as part of the history leading up to the parent of their changes, then they would have a very hard time getting their changes in place as they would potentially be unable to find a common ancestor to merge their changes into master.  

So, anytime we are rewriting history, including with an amend operation, we need to be certain that it is not on a published public branch and/or that no other team members are currently dependent on the commit where we are changing history.

Also in this video, at the time of the recording I had a personal issue with my setup - in that I wasn't waiting for code to complete to complete the commit.  I show how this happens and how it causes me to fail to amend the commit message as I wanted to.  I also show how setting the -w flag on the default editor is a remedy to this issue.  Hopefully you don't have that issue, but if you do, now you know how to solve it.

Amending Commits: Adding a file to a previous commit Preview 03:57

In this video, we take the time to work with the [git commit --amend] command one more time.  

This is just another way to practice using the command, as we can now realize that we can do whatever we want on an amend.  We could make any changes we want - add files, delete file, remove comments, fix bugs, etc. 

While the ability to amend is very powerful, once again we just need to remember that we should not be making this type of change on a published public branch.  If something is terribly wrong in the case where a branch is already published and public, other options exist, such as revert or simply just making the changes and pushing as a new commit to follow the bad one.  We could always then just tag the bad commit so everyone would know there is an issue and not to reset back to this point.

Working with the git commit --amend command

The [git commit amend] command gives us a chance to rewrite the last commit with a new commit, thereby performing updates in the case where something was missed, a bug was fixed, and/or just simply changing the commit message. This activity takes us through working with the git commit amend command

Exploring the reflog: Part 1 Preview 08:15

In this video, we take our first look at the reflog.  

As I've been showing different aspects of the repository during our activities, I've been using the 'GitViz' tool.  The thing about the GitViz tool is that it has to be getting its information from somewhere as well, right?  When we can see commits that are not reachable but still listed, there has to therefore also be a way to see this in the terminal.  This is where [git reflog] comes into play.

We start off by looking the log and noticing that only the reachable history is shown in the log, and then diving into the reflog to see the commits that are currently unreachable.

We also note that reflog actually tracks things like moving from one branch to another, and then other things like commits, merges, resets, etc.  All of the history refs contain the same syntax HEAD@{n} where n is a number from 0 - n.  The most recent item is at index 0.

We notice that we can then use the reflog to be able to determine a commit id and checkout the commit based on what we can see in the reflog.

The nice thing about the reflog is we can name a specific index, or we can start to use time differences, such as HEAD@{4.days.ago} to get the reflog starting from a specific point in history and working backwards in time.  

Exploring the reflog: Part 2 Preview 07:28

In this video, we continue our examination of the reflog.  

We start out by looking at ways we can see the differences between two different entries in the reflog.  Essentially, it's nothing different than using the direct commit id, but now we can use the reflog ids.  For example, [git diff HEAD@{2} HEAD@{7}], etc.

We then move into using timespans to see how we can compare the repository for something like [git diff HEAD@{1.min.ago} HEAD@{4.months.ago}].

Next, we note that we can use the reflog to expire unreachable commits to be immediately collected with the garbage collector.

Finally we note that anything we can do with log we can do with reflog, but we see that most of it either does no good or gives an error if we try to use it.

A simple examination of git reflog

Reviewing the git reflog can help us to see what has taken place in our local repository. This activity is an examination of how we can interact with git reflog.

Squash and Merge at GitHub: Part 1 Preview 09:08

I was so excited when I saw this feature at GitHub.  So excited that I decided that every time I merge, I would use the Squash & Merge option, because having only one commit seems to look a lot nicer than having lots of commits.  In same ways, it very much is the case.

However, the real problem comes into play when you do this because you are writing a public commit history, and it will NOT line up with your branch where the original commits take place.  Because of this, it can be dangerous to use a squash and merge without deleting the feature branch when done.  Note that I said it can be dangerous, and I did not say that it is impossible to keep using a feature branch, but I will say you should have a very good reason to keep using the same branch after squash and merge.

Squash and Merge at GitHub: Part 2 Preview 07:58

In this video, we continue working with squashing and merging with GitHub, where we now perform the cleanup so that the commits in our local history won't keep popping up as needing to be merged during each push/pull request operation.

This reiterates the point that it is a very good practice to delete the local branch as well as the branch at GitHub after performing a squash and merge.

After seeing the cleanup, we can see how nice the history looks and we know that we don't have to worry about commits that are no longer part of the history getting in our way or showing up again in an unwanted manner.

Squash and Merge at GitHub: Part 3 Preview 09:28

In this video, we're going to take a look at what it would look like if we do the squash and merge at GitHub but fail to cleanup.  It would not be impossible to keep working with this branch in the future, however it would require that we then 're-commit' the original commits that were committed before the squash and merge.

We see that GitHub is smart enough to only show the file that has been changed, even if there are multiple commits in one branch of the history that no longer exist on the second branch.

Performing a git squash and merge at GitHub to condense our commit tree.

Sometimes, when merging our changes, we might want to squash all of our commits down to just one commit. We can do this in a couple of ways. One of these ways is to squash during merge at GitHub. This activity will walk us through performing the squash and merge at GitHub

Using Aliases Preview 05:19

In this video, we are going to go over setting up aliases.  Aliases are great, because they give us the chance to condense longer commands into a short, easy-to-remember command.  Additionally, we can put commands that might be harder to remember into a simple command (for example, we could create an alias for git pull --rebase as "gpr" or git fetch --prune as "gfp".  

In our course, we've seen a couple of commands that we hit over and over again - 

[git oneline --graph]

and 

[git reflog expire --expire-unreachable=now --all]

and

[git gc --prune=now]

In this video, we'll set aliases into the global config file for each of these, so that we can easily run these commands throughout the rest of the course.

A couple of quick things to note about aliases, however.

  1. Because they are created in the global config on your user profile, they do not exist on another machine without being re-configured
  2. Putting the commands into an alias may lend itself to the fact that since we don't type these commands over and over again, we may actually forget the commands.

Finally, as mentioned toward the end of the video, due to the local nature of the aliases, we may consider adding a file to a repo somewhere that is just for our aliases, which would make it easy to restore on another machine in the future.

Using Aliases to simplify our commands

Sometimes we have commands that are lengthy or difficult to remember. We can set up some aliases to execute our commands instead of having to type the entire command every time. This activity walks us through setting up a couple of aliases.

Set your system to always prune during fetch Preview 01:47

When we have multiple developers working on a repo, we need to fetch often to get changes.  Also, as a team member, we've probably created a bunch of local branches that we've used during development.

Perhaps after we perform the commit, we delete the branch at GitHub, but never take the time to do any cleanup in our local repository.  

If we set our command for fetch to prune, we can be assured that each time we do a pull, all of the remote references that no longer have a valid branch at GitHub will be removed from our local repo.

To make it so that our system always prunes on fetch, we can add a simple entry to the global config.

Performing a soft reset Preview 06:38

As we start working with the repo, there are times we just need to get files that we had added to index back out of the added status and give us a chance to reframe what we'd like to add for the commit, or undo the changes with a hard reset or rm/clean operation.

We can see with reset that we can also go back to the previous commit by entering the previous commit id and still not lose our changes.  This is great, because it means we don't have to worry about losing our changes, even if we "rollback" to a previous version of the repository - as long as we do a soft reset.


Hard reset and clean on current commit Preview 07:49

In this video, we perform our first "hard" reset.  The major difference between a soft and a hard reset is that with the hard reset, we move the files back to the state they were in before we did anything to them.  Therefore, we can actually see how this type of operation is really useful if we start going down a tangent and want to throw everything away and start over.

The caveat here is that the untracked files will still just hang around.  We could just remove the untracked files that we had added, or we can run a clean operation to get our local working directly back to the correct state that it should be as of the last commit.

We use a couple of options flags here to make sure that we don't ignore files that are in the .gitIgnore and we hit all of the directories and subdirectories.  Also, of most critical importance is the ability to use the -i flag on the clean activity so that we can have an 'opt-out' option to make sure we don't wipe out files/folders that we don't want to lose.

Hard reset on previous commit - merge into master Preview 09:40

In this video, we take our final look at using the reset command by performing a hard reset back to a commit.  

The great thing about performing a reset is that we can go back in time to the state of the repository at the time of the reset.  As we saw in the soft reset video, this is just to the previous commit, but as we see in this video, we can go back as far as we want.

If we needed to make a change, then, we could reset back to the commit and then checkout a branch from that point.

However, we once again need to be really careful about what we are doing here, because if this is done against a public branch and we change the history by resetting and then commiting a new line and merging that into master, we could really cause a lot of problems for others that are trying to work with the repository, depending on how we merge it back.

In the video, we get to see how we could go back to a previous commit, checkout a branch, make a change, and then bring that into our master.  Certainly there are other ways this could have been done, but this gives us a decent look at how we could work with reset to help us fix a broken repo.



Learning about git reset and git clean

This activity walks us through a couple of scenarios to solidify our learning about the git reset and git clean commands

Reverting a commit Preview 04:56

There will be times when something is just not right with the latest commit.  Often, this won't be discovered until we push out to a new environment and someone else tests and determines there is a problem.  By now, our changes are in the master branch and we don't want to change a publicly published commit history.

We could just checkout a new branch, make all the 'undo' changes, and then push, but GIT has a built-in command that lets us directly undo everything that was done in the last commit.  This is really cool, because there is far less of a chance that we will miss something small that might get missed with a manual operation to revert to the previous version.

Reverting the state of the repo with a public revert commit

Sometimes we need to roll things back. There are many ways to do this, but if your commit history is public and others are depending on it, one of the safest ways to do this is to perform a revert. This activity walks us through learning about the [git revert] command.

Introduction to Rebasing Preview 06:17

In the next few videos, we're going to learn about one of the coolest operations that we can do with GIT - which is to perform a rebase.  There is nothing cooler than seeing your commit history move from one parent to another, and there is very little that can invokes as much fear in users as this can.

For this video, we just take a look at a simple demonstration to see how rebasing should work, and then we'll get a chance to apply what we've learned in the next few videos.

Working with Rebase: Activity 1 - Part 1 Preview 07:29

In this video, we will simulate two developers interacting with the repository, so we can see what it looks like to need to rebase our history after another developer had pushed a change into master.

Since we are simulating a couple of developers, this video actually gets too long and we don't get to do the rebasing in it just yet, so we'll get a chance to see that in the next video.

Working with Rebase: Activity 1 - Part 2 Preview 07:23

In this video, we continue our first rebasing activity. In order to do the operation, we first need to get master up to date and then we switch to the branch we want to rebase, and rebase master.

The GitViz tool gives us a nice view that lets us see how the rebase takes place, and of most important note is that the commit ids are changed during a rebase.  This is again why it is so critical to not do a rebase operation against a publicly published branch.

The video goes on to show how each developer can continue to rebase the changes as each make changes in the repository.

We finish up by expiring and running the garbage collector so that unreachable commits are no longer available.

Working with Rebase: Activity 2 Preview 10:32

In this activity, we're going to rework the first rebase activity, but this time we're going to see it with a conflict.

Of course when a conflict exists, the only real difference is that we'll need to resolve the merge in order to perform the rebase.

Once the rebase starts and the conflict exists, we get a very long message about what to do for continue or abort the rebase.  Also note that we get to see how many conflicts we need to resolve.

If we wanted to abort, we could easily do so by typing [git rebase --abort].  However, we're going to resolve so we use our mergetool.

After the conflict is resolved, we type [git rebase --continue] to make the rebase happen, and we note the different commit id that once again is created at the end of the rebase operation.

Another thing to note is that it's very clear at this point we are keeping a very nice, very linear commit tree.  By performing the rebase, we don't get the various branches going off in different directions from a commit and then needing to come together again with a merge.  Instead, we "start" each change after the other has already been committed.

Working with Rebase - Activity 3 Preview 09:59

In this video, we are going to see what it takes to squash our commit history locally using what's called an "interactive rebase."

This is probably one of the most fun operations we'll do, because we can immediately see how useful it would be to keep our history very clean.  Although our feature may have many commits, when we go to master we really just need the one commit that contains all of our changes.  So if we have multiple commits and want to condense, we just do a 'squash' operation via the interactive rebase.

[git rebase -i HEAD~n]   where 'n' is a number of commits to squash together

Once again, we make note that we're going to squash a number of commits into a completely new commit, which means this is rewriting history.  We do have to interact, picking the first commit, and then squashing the rest.  We then see that we get to put a commit message in place -> but all four commit messages are retained in the commit description - which is very nice!

To complete the operation we perform a pull request out at GitHub, where we also do a merge with rebase. Because we did do the rebase on the pull request, we again need to just clean up our local branch.  This time, for sure, since we are trying to keep everything linear, we definitely want to delete the branch so that we get rid of the commit that is no longer needed on the local branch that is already in master.

Rewriting our history with [git rebase]

This activity takes a good look at working with the git rebase command to change our commit history. If we want a linear history, we will need to rebase. Rebasing also provides a few more tools that give us more power over the history of the repo.

Cherry Picking Preview 09:35

Cherry picking is probably one of the more 'scary' operations about GIT -> but it shouldn't be.  There are just a few things to remember about performing a cherry-picking operation.

1) You are going to get all of the history up to the commit you are picking by the nature of the game.  

2) If all you want is one part of the commit, you should do a cherry-pick operation with a -p [patch] flag, so that you can choose the correct hunks that you want to keep

3) In the end, you'll have brought the changes up to the commit you are picking into the branch you are picking to.

In the video, we setup our cherry-pick into a new branch and have to resolve a conflict.  Just like with rebasing, we see that the command lets us know we are in the middle of a cherry-picking operation.  Once again, at any point we could get out by using the --abort flag [git cherry-pick --abort].  To finish, we can just commit the resolved merge.

We then finish up with a merge with rebase, which means we'll need to wipe out the branches after to avoid having history conflicts.


Performing a git cherry pick to 'pick' a specific commit into our repository.

Sometimes we have a chain of commits and part of the chain needs to get into production as quickly as possible, but perhaps another part is not quite ready. In situations like this and similar situations, it is appropriate to get just what we need via a cherry-picking operation.

Stashing Changes Part 1 Preview 09:42

When I first started with GIT, one of the things I wanted to learn more than anything else was stashing.  This is because I came from a TFS background, where we would do what is called "shelve" changes.  In essence, the stash is a lot like a shelveset, however, the advantages are real in GIT - for example, I can repeatedly apply a stash across any branches.

In reality, I've found less and less use for stash.  The reason for this is simple.  It is easy and inexpensive to create branches in GIT.  Therefore, for 90% of what we are doing, if the first thought is 'stash' it, the next thought should be 'why not just branch and commit and then go back to the original branch which would be back to the original state of the original branch, AND our changes would be easy to find and apply at anytime via a merge or pick with patch.

One useful thing I have found with stashing in the C#.Net world is to stash local web.config changes so that I can easily re-apply my database connection string for my local database - which I never want to commit to a public repository that should be pointed at Test or another common environment.

In this video, we start looking at stash, and see what it means to use git stash list, git stash save, git stash pop, and git stash apply.

Stashing Changes Part 2 Preview 07:15

In this video, we continue looking into how we might use git stash to work with changes across branches that we don't want to commit or that we want to re-apply over and over again.

We then look at how to cleanup our stash by individual stash indexes, as well as the full stash clear.

Another thing that is interesting is we can also checkout a new branch based on what is in stash (but note that this will REMOVE the stash item, so if it's something that needs to be persistent the stash would need to be re-created after checking out the branch from stash.


Working with git stash

Being able to save our progress without committing might be nice. Also, it's nice to have some sort of way to apply some changes over and over again, even across branches. Using the stash is a good way to do this.

Tagging Preview 10:35

In this video, we take a look at tagging our commits.  Tags are awesome, especially when we realize that creating a tag essentially creates a release at GitHub that can easily be downloaded or checked out [just like checking out a commit, we can checkout by tag].

There are two types of tags that we need to be aware of - lightweight and annotated.  A good common rule-of-thumb is that if the tag is local to you, you can use a lightweight tag.  If the tag is going to be public, you should probably make an annotated tag, because it has nice information about who, when, etc, in the object.

We take a look at how to both push and delete tags from the remote repository, and we also take a look at how we can search all of our tags by some wildcard searching.  We also look at how we can delete tags from our local repository.

Finally, there is a setting we can put into our global config for making sure that whenever we push, we also push any tags using

git config --global push.followTags true

Tagging our repository

Tags are useful for bookmarking commits, especially for releases or different important state information. This activity helps us to work through a couple of different tagging scenarios.

Conclusion & Next Steps Preview 01:31

Congratulations! You made it to the end of the course!  Not everyone can say that so you should be very proud of yourself.

In this course, we covered a lot of the more advanced GIT commands, including:

  • git commit --amend
  • git reflog
  • squashing and merging at GitHub
  • git config --global alias.x
  • git reset
  • git reset --hard
  • git clean
  • git revert
  • git rebase
  • git cherry-pick
  • git stash
  • git tag

Although this course got us to the level of "very good" with GIT, it will take practice and real-world experience to be an expert.  That being said, I do hope that this course has positioned you to be the person on your team that everyone turns to when stuff goes wrong.

For next steps, you can continue to work with these commands in more detail, review the documentation online and keep growing your skills with GIT.  Additionally, there are more advanced commands that we did not cover in the course and we are certainly going to need to keep working with GIT to keep our skills sharp.

Once again, thank you for the chance to be a part of your journey, and I wish you all the best in the future!