Hone your Mad Git (and Terminal) Skillz - Episode 1

If you have traveled a bit with me thus far, I may have exposed you to many different Git commands. Lets work through a pretty extensive overview of Git.

Let me start by recommending this video. This will give you a pretty solid understanding of the basic architecture of git commits and how they can relate to each other.

Git is a version control system. That means that Git can record “versions” of a project as many times as you want. It does back up all your files, but also backs up each change you make when you tell it to do so. So if you are working on controversial album art for a music project you are working on, you can save each little change made, and if you decide that you want to go back to how you had it in the beginning, you just check out that commit. Or if you want to see who was responsible for a certain image being added, you can see that information too.

Git is also distributed, and is often called a “distributed version control system”. That means that in addition of the above, the entire project history and log and contents and everything can be distributed on several computers in different places. You have your project up on GitHub (which is totally amazing and we will talk exactly about that next time), you have that project local on your computer, and your good friends Steve, Eric and Ginger have local versions on their machines too. So if you spill a delicious Rose Kombucha all over your computer, your entire project isn’t lost. You will need to get another computer and set it up, but then you just fetch and merge changes from other repositories (where you have that project saved as a Git project). Each repository has the entire contents of the project including all the history so you don’t lose a thing, as long as you are active in “pushing” your changes.

Now it’s your turn! Lets start by making a directory, cd'ing into it, and initializing an empty git repository.

You might have seen that ls -l lists your files and directories, and ls -al lists all those plus hidden files and directories. Oooh, look, a new hidden directory .git. What is it?

$ cd .git
$ ls -al

Whoa, look at all that stuff! Those are the Git internals… the pieces that keep track of all your work and ordered history. Let’s definitely not mess with any of this stuff. Unless of course you accidentally initialize a git repo… if that ever happens just delete this .git directory.

$ cd ..

We should be right back in our blind_faith folder. Let’s put a text file in there.

The echo line is appending (placing it at the end) the text between echo and >> into the file cant_find_my_way_home.txt. Since it is an empty file, it just puts it in there. If you now open the file in your text editor, you can see that that text has been added. Let’s commit this!

This is another way of adding changes to be committed. The -p flag allows you to approve “patches” of code. You then can sequentially go through each patch or hunk and selectively approve them. For each hunk, these are commands most used:

y - Yes, stage it

n - No, don’t stage this one, but show me the next hunk.

q - Quit, don’t stage this one and skip all the rest too.

a - All of the rest. Stage this one and the rest of the hunks too.

d - Don’t stage any of the hunks in this specific file.

Approve the second line with a y. If you would like a full list of commands available, enter git add --help and press the spacebar to page down. Enter q to exit the help. Let’s commit this change.

Oh no! What is happening? Well, check that single quote up there… terminal is thinking that you are putting things in quotes. Any time terminal gives you that little caret thingie, it is waiting for more information. Let’s control+C to terminate this command and try again.

$ echo "You are the reason I've been waiting so long." >> cant_find_my_way_home.txt

Better! If you have single quotes in a string, be sure and double quote the entire string to avoid trouble. And another commit.

Did you see how the git add -p shows you exactly what line is added with the little + symbol? You also are shown the context of that added line to help jog your memory of what that line is doing there and how it relates to the rest of your files. Let’s see what we have so far.

$ git log --oneline --decorate --graph --all

You can see our most recent commit at the top with the tags HEAD and master. Our main branch is always called master and wherever it is we are currently standing (mostly) is called HEAD. Let’s make a new branch to see what that looks like.

That first command does two things, it creates a branch (due to the -b flag) named winwood, then checks out that branch. When you run git status you can see that you are in that winwood branch. And running that log will show you all your tags again… looks like our new winwood tag is right there along with the master and HEAD. Let’s add some more!

Now Eric, Ginger and Ric are giving the thumbs-up to Steve on the new lyrics addition. Let’s merge our two commits on our branch into our master branch. First order of business will be to “stand” in the branch we want to merge into. We want to merge winwood INTO master, so we will need to checkout master.

$ git checkout master
$ git log --oneline --decorate --graph --all

As you can see, our HEAD tag and our master tag are now on the same line. Also, if you run git status again, you will see we are checking out our master branch. Now on to merging. Look at that git log again… see how master is a direct “parent” of winwood? This will be a “fast-forward” merge… we don’t need to do anything special for this merge, we just need to move that master tag up to the winwood tag.

$ git merge winwood
$ git log --oneline --decorate --graph --all

As you can see, git told you that it did a “fast-forward” merge. This means all git has to do to merge the old commit with the new is move a tag because the old is a direct descendant of the new. Let’s imagine that Steve and Eric are both working on this album at the same time. First, let’s make a change in the master branch. We should be in the master branch, but run git status if you ever need to check.

A screen should pop up with a commit message of “Merge branch ‘winwood’”, and this is totally sufficient. You can close this screen by pushing :q and enter, and it will save that message. This time, we didn’t just fast-forward with our merge, we actually made a new commit combining the two commits. Since there are no merge conflicts, git could totally handle this without any help. Yay git! Now onto merge conflicts… we should be in the branch master.