Want to see the full-length video right now for free?
Welcome to our Mastering Git course!
In these videos we'll teach you everything you need to know to about Git to work efficiently and confidently.
This first video is focused on getting confident working within your repositories. Later videos will cover many different workflows, commands, and configurations. This video will make sure you're comfortable trying them all out, and not worried about "breaking" a repository.
Before moving on, we do want to highlight that this course is not intended to be your introduction to Git, but instead expects that you're familiar with core operations like staging and committing files, branching, viewing the log, and pushing to GitHub. If you're not quite there, we recommend starting with a few introductory resources, then coming back here when you're ready:
One of the key features of my command line Git workflow is having the current Git context always displayed as part of the prompt. In particular, the prompt will display each of the following (depending on the current Git context):
This context is critical to my being able to confidently work with my repo, helping me to avoid common mistakes like committing to the wrong branch, forgetting to commit a specific file, etc.
The thoughtbot dotfiles contain a streamlined Git info segment, and my personal dotfiles contain a Git prompt configuration that includes the branch, current commit hash, and dirty status (note, this relies on some features of oh-my-zsh to display properly). Another option would be to use the excellent pure prompt for zsh which contains all this and more, but is still nice and snappy.
Commits are a safety net, protecting you from any mishaps down the road. They're like save points in a video game and you can never have too many. Likewise, you can always reorder, combine, or even remove commits from your history if you want to clean it up later. Once you've made a commit, it's darn near impossible to lose that work without trying to.
I've never regretted making a commit, but I have regretted not making a commit. So, err on the side of caution and commit all the time!
git stash
is a command that will grab all of the changes in the working
directory and store them away. This allows you to focus on an emergency bugfix
or similar, and later revisit the code you had stashed away.
This of this command as your panic button. Need to make an emergency change on
another branch? Running off to lunch and not sure what to make of your
experiment? git stash
has your back.
The one caveat that makes git stash
slightly less than ideal is that by
default it will only grab changes to files already known to Git. This means it
will leave behind any new or untracked files. When I run git stash
I want it
to grab everything and get back to an empty status, but unfortunately this is
not the default.
Luckily, we can solve this with the -u
, "include untracked", flag to the
stash
command. There isn't a way to make this the default
behavior, but from now on, feel free to always use the -u
flag and stash
will work as expected:
$ git stash -u
The reflog is Git's internal record of every explicit change we've made. Any
time you commit, reset, branch, merge, or otherwise update what Git is
focused on (technically what HEAD
is pointing at), Git makes a record of
that.
Likewise, since everything in Git is immutable, all commits stick around even after we perform a seemingly destructive action like rebasing. With the reflog, we can look up these forgotten commits and restore them easily.
We won't go into detail here as our goal is not to master the reflog
command, but instead simply introduce it to give us that last little bit
of confidence as we try out more advanced commands within our repos. As long
as we follow the golden rule of committing all the time, the reflog will allow
us to get back to any version of our code we need.
The reflog can be viewed with the bare git reflog
command.
$ git reflog
3001aaf HEAD@{0}: pull: Fast-forward
1576f8b HEAD@{1}: pull: Fast-forward
7caa99e HEAD@{2}: merge update-rss-summaries: Fast-forward
1a8a17d HEAD@{3}: checkout: moving from update-rss-summaries to master
7caa99e HEAD@{4}: checkout: moving from master to update-rss-summaries
1a8a17d HEAD@{5}: checkout: moving from update-rss-summaries to master
7caa99e HEAD@{6}: rebase -i (finish): returning to refs/heads/update-rss-summaries
# ...
The reflog lists the commit and operation for every single command that changes what we currently have checked out in working directory. Every commit, branch, checkout, rebase, reset, etc. all are tracked, and from this history we can restore any version of the code.
The reflog can be focused down to just a specific branch by adding the branch name as an argument.
$ g reflog show update-landing-page
300b862 update-landing-page@{0}: commit (amend): Add bundler-audit to check gems for security issues
09682a4 update-landing-page@{1}: reset: moving to HEAD^1
a3b5690 update-landing-page@{2}: commit: Update gem versions based on bundler audit report
09682a4 update-landing-page@{3}: commit: Add bundler-audit to check gems for security issues
6a327f3 update-landing-page@{4}: branch: Created from HEAD
From there, you could restore your branch to a previous commit, for instance
09682a4
, with:
$ git reset --hard 09682a4
With that, we've laid the foundation for the remainder of this course. With
the combination of Git info in prompt, using git stash -u
as our panic
button, committing all the time, and knowing that the reflog has our back,
we're ready to confidently move on to the more advanced commands and workflows
covered in the remaining videos.