Stop whining about "losing your files" or "accidentally deleting the Grand Master's ASCII foot pics." I'm Darth Awesome, and I’m here to teach you how to manage your code like a true Sith Lord.

Git is a version control system. It is not optional if you want to be taken seriously as a developer in this galaxy. Git tracks your files as they change, allowing you to travel back in time to before you broke everything. It allows multiple nerds to work on the same project without Force-choking each other.
This course is meant to beat the basics of Git into your skull. You mess with Git using two methods: the Command Line (for those who crave true power) and VS Code (for those who like pretty buttons). This isn’t a course about how to use the command line or VS Code. I’ll be nice and give you command line commands through this course—you can copy paste commands into a search engine of your choice to figure out how to actually do the operation in whatever tool you are using. Don’t be lazy.

Git was created by Linus Torvalds, the same guy who made Linux. He created it because he was angry. Blah blah blah. Now it is really popular. What? You thought I was going to write it all out for you? Pffft. Go read about it yourself if you want to be a nerdy Jedi.

You’re going to sit down and shut up while I fill your tiny mind with the following information:
Installing Git Configuring Git The database & the commit The fancy graph Branches HEAD & detached HEAD state The three areas for your code Undoing things Recovering your screw-ups My Sith Git cheat-sheet Recap
Obviously you need Git. Download and install it so you can experiment. If you have a Mac, chances are you have it already. If you have Windows (or you discover your Mac is missing it), you can head here to install it. To use Git, you need a terminal, an IDE (Integrated Development Environment), or other git tools (there’s a lot). We’re going to keep things real simple for you.

However, we also live in a modern age of laziness. VS Code (Visual Studio Code) has Git built right in. We will cover both. Real power lies in the terminal. Sissies use the GUI, but you can be a sissy if you want. Most people won’t judge you, but I will.
The most important thing to do now that Git is installed is to make sure when you do commits, Git knows who you are. The two most basic commands for this are
git config --global user.name “Darth Awesome”
git config --global user.email “darth.awesome@brotherhood.lol
The FIRST thing you need to get embedded in that noggin’ of yours is this foundational understanding that makes a lot of other things make sense. Maybe you’ve learned about Git from some lame Jedi holocron and think you know what you’re doing. Forget that bantha poo doo. Let’s start from square one.
Git is a database. A commit is a record.
It isn’t a traditional database that you typically imagine being made up of rows and columns. Instead, this big bad mama jama’s fundamental unit is the commit.
What’s a commit? Glad you asked. Think of it as a snapshot. A complete holopic of your entire project at one moment in time. Not the changes you made… the entire state of every file in your project.

Each commit contains three things:

That seemingly random mix of letters and numbers is the commit pointer, or, commit hash. It is a unique SHA-1 hash that is actually 40 characters long and made up of hexadecimal characters (0-9 and a-f). Commit hashes can often be abbreviated as the first 7 to 9 of those 40 characters.
When you make a commit, Git saves a full state of your project and links it back to where you were. Because each commit points back to its parent, it makes a chain of commits aaaaaaalllll the way back to the first one in your project. Keep in mind that child commits know who their parents are but parents never know their future children. Kind of like me and my children.

There is an exception to the single parent rule. That’s called a merge commit and I’ll talk about that in the next section.
Life is pain and suffering. It would be easy if we all just committed one thing after the other. But developers live in a constant state of chaos, so coding is much messier than a straight line. You branch off to build a feature and at the same time, another Sith might branch off to fix a bug. Now you have two completely different commits with the same parent. Then those branches are merged together (with a merge commit) that has two parents!
This sexy little structure is called a DAG (Directed Acyclic Graph). Which sounds intimidating but it really isn’t unless you are a scared little porg.

This graph is your project’s history. Every branch, every merge, every decision you fools make are captured in this structure. Because every commit is a complete snapshot, you can jump to any point in the graph and see your project exactly as it existed.
The graph can get crazy complicated. Navigating it can be a pain in the butt if you had to remember all of the commits yourself. For little pansies that have trouble remembering commit hashes (which is everyone except me), we have branches. They seem more complicated than what they are.
Well, they aren’t complicated. They are just a name and a commit hash (a pointer to a commit). That’s it.
When you create a branch called feature/ortolan-farts, Git creates a small file that says feature/ortolan-farts points to commit ad7f64a. Branches don’t contain commits. They just point to them. Every time you make a commit in a branch, the branch name just points at that latest commit. It doesn’t technically know that there were 12 other commits in the branch—it just points to that new commit and then the commit points to its parent and so on.

We have commits. We have branches pointing at commits. How does Git know where you are and what you are working on?
Meet HEAD. HEAD is Git’s way of tracking your location. It’s another pointer, but usually instead of pointing out a commit, it points at a branch. When you’re on the main branch, HEAD points to main. Main points to a commit. That’s your current location.
If you run git checkout feature/ortolan-farts, the HEAD moves to point at that feature branch. You’re now working on that branch.

Neato. This all seems straightforward and easy. Soooo let’s complicate things. HEAD doesn’t have to point at the latest commit in your branch. Nope, we can move backward in time and check out specific commits via git checkout bb8c3do that is somewhere earlier than your latest commit in the branch. This moves HEAD to point at that commit directly. This puts you in a detached HEAD state.
Sounds scary. WELL IT ISN’T! You just need to understand what’s happening. You can still work. You can still commit. But no branch is following along. Any commit you make from that point forward is considered an orphan commit. It will know its own parent, but it doesn’t have a branch at all. This is dangerous because it is just floating in space and will be garbage collected and disappear.

The best way to avoid this stupid mistake when you want to make a change from some point in the past is the following. Change the HEAD to the old commit then make a new branch. That new branch will point at the old commit and then any new commit in that branch will then be pointed to by that branch.
I’ve forced info into your brain about how commits are organized in your repository but how do files get committed? What happens before they are committed? Do you always have to commit all files you’ve changed? HECK NO! Only barely sentient creatures would think that nonsense. Git actually has three areas where your code can live.

git add, you’re moving those changes to the staging area—you are basically saying “I want this in my next commit.” When you git commit, Git takes everything in staging and creates a commit, which does the whole snapshot thing.
Why does this matter?
Well, because this allows you to be picky about what goes in a commit and it helps give you options for how you can undo bad code that you’ll inevitably write.
# Undoing Things
Your code—like the Force—is always in motion. When you make mistakes, Git provides a handful of ways to recover from those mistakes with four commands. Checkout, Reset, and Revert. These are very helpful, but can cause you to lose work if you don’t know what you are doing. That’s where I come in to save the day.
## Checkout
Checkout moves HEAD. You can checkout a previous commit to go back in time, start a new branch, and try something new. When you use git checkout, you aren’t losing anything. The commits still exist in your Git repository, you are just changing HEAD to point to something different—like a different branch or a specific commit.Checkout is safe and non-destructive.
Accidentally added a file to the staging area? Restore can help by undoing your git add. You can git restore --staged file.txt and make file.txt not staged anymore and with the changes as part of your working directory.
Have some changes on a file that you want to get rid of? You can discard all changes on a file by doing git restore file.txt. NOTE: This is destructive and you will not be able to recover the changes that you discard.
Reset is even more dangerous. Reset moves a branch pointer. If you move the branch to an older commit, the newer commits that were formerly part of that branch’s tree are orphaned. And, if you recall, those will eventually be cleaned up by garbage collection.

I actually use git reset a lot because I like destroying things. There are three modes:
git reset --soft): This moves the branch. Any undone changes remain in the staging area awaiting a new commit. You can use this to turn X number of commits into a single commit.git reset --mixed): This moves the branch. Any undone changes exist as changes to your local working directory and are not in the staging area. You can use this to split X number of commits into different collections of commits.git reset --hard): This moves the branch. The staging area is reset. The working directory is reset. You will lose work with this. You can use this to go scorched earth and start over from a particular commit.Warning: For any reset command, you should only do this with commits that you have not yet shared with anyone because it changes commit history.
Revert allows you to undo work without moving any branches. Without abandoning any commits or code. It is helpful when you want to undo something that you’ve already shared with someone or pushed up to a remote repository (like GitHub). You simply git revert HASH and it will make a new commit undoing the changes from that HASH. If you were feeling saucy, you could revert your revert by doing git revert NEWHASH.
Quick summary: Checkout moves HEAD and is safe. Restore rolls back staging or local changes and is risky. Reset moves a branch pointer and potentially resets the working directory and is risky. Revert does the undo as a commit so all history is preserved and is safe.
So you were flying a little too close to a star and you screwed things up? You did a hard reset? Your commits are gone.

Run git reflog. The reflog shows everywhere that HEAD has pointed to recently. Every checkout, every commit, every reset. Those lost commits from your reset, maybe you learned about rebase and made a mistake there. The commits are probably still in your Git repository. A reflog will show you hashes. Find the one you are looking for and create a branch pointing to that branch and BOOM. Recovered.
There is a timer on reflog entries—the expire after 90 days for reachable commits and 30 days for unreachable ones. If disaster struck 5 minutes ago, you’re probably fine.
These are the most common commands badass Sith like myself keep on hand. Some of these are discussed in this course and some are shown so you can do some digging on your own because I don’t want to do all of the work for you.
| Command | Description |
|---|---|
| git init | Initializes a new Git repository in your current folder. |
| git status | Shows you the state of what is modified, what is staged, and what is untracked. |
| git add <file_or_dir> | Moves changes for the file or directory from the Working Directory to the Staging Area. |
| git add -p <file_or_dir> | Allows you to interactively stage some of your modifications from the Working Directory into the Staging Area. |
| git commit -m “MESSAGE” | Takes everything in the Staging Area and saves a permanent Snapshot to the Git repository as a commit and moves the branch pointer forward. |
| git log | Lists the history of commits for the current branch, starting from HEAD and working backwards. |
| git branch <name> | Creates a new branch on the current commit. Does not switch to the branch, though. |
| git checkout <name> | Moves HEAD to point to the specified branch or commit. Updates your working directory to match the commit. |
| git checkout -b <name> | Shortcut: creates a new branch and moves HEAD to it immediately. |
| git merge <branch> | Joins two lines of history. Creates a new merge commit with two parents. (current branch + target branch) |
| git restore <file> | Destructive. Copies the file from the Staging Area into your Working Directory. Used to discard local changes. |
| git restore --staged <file> | Safe. Removes a file from the Staging Area but keeps your edits in the Working Directory. (Undoes `git add`) |
| git reset --soft <commit> | Moves the Branch Pointer backward. Keeps your changes staged so you can commit them again. |
| git reset --mixed <commit> | Moves the Branch Pointer backward. Places your changes as changes in the Working Directory, unstaged. |
| git reset --hard <commit> | Moves the Branch Pointer backward and destroys all work (staged and unstaged) after that point. |
| git reflog | The safety net. Shows a log of every movement HEAD has made (even the ones you “deleted”). Use this to find lost commits. |
| git fetch | Downloads new data (commits, branches) from a remote repository (like GitHub) but does not touch your local branches. It just updates the repository. |
| git pull | Does a `git fetch` followed immediately by a `git merge`. It updates your current branch with the remote changes. |
| git push | Uploads your new local commits to the remote repository and moves the remote branch pointer forward. |
Let’s summarize what we’ve talked about.
Git is a database of snapshots (a.k.a. commits). Commits point to parents forming a graph. Branches and HEAD are just pointers to commits. Checkout moves your local working directory to reflect what’s in a commit snapshot. Reset moves branches. Restore undoes stuff. And when everything goes wrong, reflog.
Take the quiz and pass, or these 3 kittens will die.

The bulk of the flow of this course was based off of Git Will Finally Make Sense After This with some info pulled from Git Explained in 100 Seconds and various other sources including Darth Awesome’s brain. The videos are great at articulating the above with nice visuals. At the very minimum, watch the 100 second video because it is flipping short.
Please log in to take this course's exam