Don’t Panic! It’s Confusing for Everyone

Git is a powerful VCS (Version Control System) that is the industry standard for tracking any and all of the changes that take place on a project. It’s utility comes from it’s ability to allow team leaders to conveniently manage multiple members contributions and incorporate them into a finished project. Unfortunately, it seems to be designed from the point of view of those team leaders and things can get pretty confusing if you’re one of the people doing the contributing.

I know when I first started using git, I had difficulty following exactly what happened when I typed something into my terminal. I didn’t understand why I had to git add before I git commited or what the difference between my upstream and origin were. What was the difference between pull and fetch? None of it made any sense and I just tried to follow the workflow that had been outlined, completely unable to troubleshoot.

GitHub likes to think that the average git workflow will end up looking something like this:

Branching

That may be the case if working with only one or two other people on a small project. However, once you get to a corporate level, working in conjunction with hundreds of other people, things start to look a little more like this:

Development Repos

While there’s no arguing the necessity of such a complex Development - QA - Production environment, it’s downright intimidating when you can’t even follow what’s happening on your own machine!

It’s Where You Work

Git Workspace

In order to understand everything that goes on behind the scenes of the git commands you type in your CLI, you first need to understand what the scenes themselves are. On your machine, there are several different areas of memory that git will operate within. First, let’s take a look at the one your probably most familiar with: Your workspace.

[timestmp] code
// ♥ mkdir git-practice
[timestmp] code
// ♥ cd git-practice/
[timestmp] git-practice
// ♥ git init
#=> Initialized empty Git repository in /Users/flatironschool/Development/code/git-practice/.git/
[timestmp] git-practice
// ♥ ls -a
#=> .	..	.git

You’ll notice that this will initialize a local repo (repository) inside of the workspace in a .git folder. A similar process happens when you git clone git@github.com:username/projectname.git, the only difference being that you will end up with the repo you’ve cloned in your workspace as well. This distinction took me some time to realize. Your workspace is not the same as your local repo. This means that when you git push, your workspace isn’t necessarily the code that you are pushing.

The workspace is the place where you’ll be doing all of your work. You should feel free to hack and slash apart the code here to your hearts content. If at any point you think you need to undo some of your changes, you can simply git checkout HEAD or git reset --hard (they do the same thing) and that will change your workspace back to what is stored in your local repo.

In what?

Git Index

Next is probably the most confusing part of your local git environment, your index (or stage, or cache). This is where the files you are about to commit go. Whenever you git add, the index gets populated with whichever files you are adding. Git will use a variety of different words to tell you this (because consistency would be too simple). Below, you can see them refer to the index in the line (use "git rm --cached <file>..." to unstage). In this example, both cached and unstage are describing different actions being done on the index.

[timestmp] git-practice
// ♥ touch practice_file
[timestmp] git-practice
// ♥ git status
#=> On branch master
#=>
#=> Initial commit
#=>
#=> Untracked files:
#=>   (use "git add <file>..." to include in what will be committed)
#=>
#=> 	practice_file
#=>
#=> nothing added to commit but untracked files present (use "git add" to track)
// ♥ git add .
[timestmp] git-practice
// ♥ git status
#=> On branch master
#=>
#=> Initial commit
#=>
#=> Changes to be committed:
#=>   (use "git rm --cached <file>..." to unstage)
#=>
#=> 	new file:   practice_file

Note that depending on which version of git you are using, git add . doesn’t necessarily add all of your changes. You should always do git status between your steps, but if you want to be extra sure git add -A will take care of that for you.

[timestmp] git-practice
// ♥ git commit
#=> [master (root-commit) bfbd8a2] My initial commit
#=>  1 file changed, 0 insertions(+), 0 deletions(-)
#=>  create mode 100644 practice_file

At any point you can view the history of your repo with git log.

[timestmp] (master) git-practice
// ♥ git log
#=> bfbd8a2 My initial commit (szrharrison, <time> ago)

We can see that, now that we’ve committed, our index is empty

[timestmp] (master) git-practice
// ♥ git status
#=> On branch master
#=> nothing to commit, working tree clean

Note that git checkout will first look in your index, and then in your local repo to get the file you are checking out.

Going Local

Git Local Repo

This brings us to the last key element of your local git environment: your local repo. Your local repo is your personal source of truth for the project. Any code that lives here should be ready to be shown to the rest of your team. In order to get any code onto your local repo you need to have written a commit message, so hopefully you were sure that it was a change you wanted to make. In case you change your mind and want to revert back to a previous commit, you can always git reset --hard <commit hash>. Note that this is a very powerful command and should only be used for commits that have yet to be pushed to the remote repository since you are essentially rewriting history. For an overall view of your local git environment, take a look at the image below (I didn’t cover the stash in this post because it’s not something I see used very often):

Git Transport

And for tips on when and how to beautify your commit history (required sometimes when committing to an open source project) take a look at this image. (Note: git revert will actually create a new commit in which the changes from the reverted commit are undone as opposed to git reset which actually erases the reset commit from your history.)

Git Pretty