A Guide to Git: The Fundamentals

Nilay Majorwar
Programming Club, IIT Kanpur
11 min readJan 15, 2021

Over the past year, I’ve seen a lot of students having trouble with using Git effectively. For a lot of people, using Git simply means knowing a certain set of commands that you do when you want to commit, a certain set for pushing or pulling. And if there’s a merge conflict, run to someone who’s done it before for help.

xkcd #1597: The state of most beginner programmers who “know” how to use Git.

And honestly, I think it’s a phase in every programmer’s curve — myself included. It took around a year of programming (and using Git) to actually understand what Git is, and to be able to resolve most Git-related issues easily.

This three-part guide is an attempt to teach (or re-teach) Git in a better way, so that you understand what happens backstage with each Git command you execute, and not become someone who only knows how to use Git.

And it’s really, really, much easier than you think.

So what is Git, then?

Git is a version control system. It helps the user in maintaining various versions of a project. It’s not the only one, by the way — there are alternatives like Mercurial and SVN, but Git rocks so much more that nearly no one uses anything else. Maybe because it’s made by the same guy who created Linux.

The classic “solution” to managing versions

So if you’ve ever done the above, Git is a much easier, cleaner and maybe even safer way to do what you want to. Really, that is pretty much all Git does at the core — it maintains versions of something.

If you like analogies, Git is a butler standing by your work table. Imagine you start writing a new novel and tell the butler to keep track of your work. Now whenever you make any significant changes to your novel (say you just renamed Emma to Clara), you show the butler your changes saying “hey, I just renamed Emma to Clara” and the butler will remember it. Now a month later you can say “hey butler, you still remember how things were when I renamed Emma to Clara” and the butler can read out the whole novel like it was after the renaming. That’s what Git does — it’s simply a bookkeeping butler.

Before we start with the series, let me clear something out: you might have heard of GitHub, but remember that Git and GitHub are way different. GitHub is an online platform that uses Git for version management and gives you access to some Git operations through the GUI, rather than using commands. This does not mean GitHub is a GUI for Git — these have their own different uses, as will be apparent in later parts.

Pre-Requisites

This guide does not assume any prior knowledge or experience with Git or any other version control system, but knowledge of basic commands like cd and mkdir will really help in understanding and following the guide.

Setting Git up

This is platform-dependent, so I won’t cover the process here. The GitHub guide to installing Git is pretty good, so follow that to install Git on your system.

For Windows users: If the Git installer offers to install Git Bash, go for it. It offers a similar command-line environment to what I’ll use in this article.

To ensure that Git is properly installed, the command git version should output the version of Git you've installed. If it outputs something that's not "command not found", you're probably fine.

Then, you must add your basic information to your Git installation — this is necessary to use Git. To do this, execute the following commands, replacing the name and email ID with yours:

git config --global user.name "John Doe"
git config --global user.email "johndoe@example.com"

If that works correctly, you’re good to go.

Some basic terminology

Before we start playing around with Git, let’s get our heads around a couple of terms that are extremely important to understand what Git does behind the scenes. It might not make sense right now, but everything will hopefully fit in by the end of the article.

Repository

A repository represents a piece of work that you want Git to maintain for you. On a computer, this “piece of work” refers to a single directory — so if you’re writing a novel and you want to use Git, you’d create a folder for the novel, keep your work inside that folder and tell Git to keep track of this folder.

Commit

A commit is the unit of change in Git. So when you “commit” your changes to Git, you’re basically saying “here Git, I made these changes to the piece of work, have a look” and Git remembers it. Showing the butler your changes when you renamed Emma to Clara is simply making a commit of your work.

Starting the book

Okay, so with everything finally set up, let’s start writing a book of nursery rhymes, because why not — it’s low effort and has never-ending demand.

We will be writing our book in multiple text files, with one file for each nursery rhyme. So let’s first create a directory for our novel, I’ll call it “poems”.

mkdir poems
cd poems

So we made a directory for our new book. Let’s now initialise the Git repository for this directory.

git init

Yeah, as simple as that. git init tells Butler Git that everything in the current directory is a piece of work that Git needs to maintain. Notice that executing this command creates a hidden directory .git in the current directory. This is the butler's personal diary - whatever updates you give to Git about your work, Git keeps it here.

Before we start with our repository, a few points to take care of:

  • To execute Git commands for a repository, you have to be inside that project directory. Every repository has its own .git directory that stores data about that repository.
  • In all code blocks used in this guide, lines starting with a # (hashtag) are Bash comments and are used to describe what the command does. You don’t need to execute these on the terminal.

The First Poems

Right now, Butler Git only knows you’ve started writing a book. So let’s write the first rhyme. Create a file named poem1.txt and write the first rhyme there. Here's what I have for the first one:

Jingle bells, jingle bells
Jingle all the way
Oh what fun, it is to ride
In a one-horse open sleigh!

(yes, not very impressive, I know)

So now that we’ve written the first poem, we should tell Butler Git about our progress. Or in Git terminology, we need to commit our changes. But before that, let’s try a commonly used command: git status. The output should be something as follows:

On branch masterNo commits yetUntracked files:
(use "git add <file>..." to include in what will be committed)
poem1.txt
nothing added to commit but untracked files present (use "git add" to track)

This is a staple command of Git that shows the current status of the repository. Most importantly, it shows the changes you’ve made since the previous commit, including modified files, untracked files (i.e new files) and deleted files. poem1.txt is a new file, so it's listed under "Untracked files".

Now, committing changes to Git is a bit of a multistage process. It’s a combination of two steps:

  1. “Staging” your changes: Here, we select what changes we want to actually commit to the repository. If you’ve made multiple changes, you can choose here what changes you want to inform the butler about. It’s like sending some (or usually all) of your changes to the stage for Butler Git to see.
  2. Committing your staged changes: Once we know what changes we need to commit, we write a brief message that describes the changes we’re committing, and then make a commit with this message.

So let’s do it.

You stage your changes by adding your changes to the stage. If you’re in the poems directory, execute the following command to add changes in the poem1.txt file to the stage.

# Stage changes in poem1.txt
git add poem1.txt

Try git status again, and it should show poem1.txt as a staged change. Let's commit this staged change now. Since the change we're going to commit represents the addition of the first poem, "Add poem 1" is a pretty good commit message.

# Commit (staged) changes to repository
git commit -m "Add poem 1"

There we go, you just did your first Git commit! Remember, a commit takes all of your staged changes and submits it to the repository. So stage only those changes that you want to commit to the repository.

Let’s add another poem:

Twinkle twinkle, little stars 
How I wonder, what you are
Up above the world so high
Like a diamond in the sky.

Follow the same process as above: stage and commit. “Add poem 2” is a good commit message.

Viewing history and checkout past versions

Let’s add another poem and commit the changes. As usual, we’ll keep the commit message as “Add poem 3”.

Baa baa black sheep, have you any wool? 
Yes sir, yes sir, three bags full.
One for the master, one for the dame,
And one for the little boy who lives down the lane.

Now with a Git-managed project, the butler knows the full history of how the project was done — let’s try it out. Execute the command git log. You should get an output similar to the following:

commit db57112cadfe51f65d026d9f51aecb792a7fef43 (HEAD -> master)
Author: John Doe <johndoe@gmail.com>
Date: Thu Dec 31 20:57:27 2020 +0530
Add poem 3commit f8dad3229118769a6b57eef76462845cadcd9efd
Author: John Doe <johndoe@gmail.com>
Date: Thu Dec 31 20:56:44 2020 +0530
Add poem 2commit 2df75a984cf42aa02cb28ec4344d1c155e43f718
Author: John Doe <johndoe@gmail.com>
Date: Thu Dec 31 20:55:49 2020 +0530
Add poem 1

git log shows you the history of commits made in the current repository, with latest commits at the top. Note that each commit is associated with:

  • Commit hash: the long hex string in each commit. It’s unique for each commit.
  • Author: the person who made the commit — in this case, you.
  • Timestamp: the date and time at which the commit was made

Ignore the (HEAD → master) part for now - we'll come back to it later.

I know, recording project history isn’t really a killer feature. But going back in history is, so let’s try doing that. Let’s go one commit back in the project — or in Git terms, let’s checkout the project a commit back.

# Checkout a project one commit back
git checkout HEAD~1
# The output may look a bit scary but don't worry, you're fine.

Once you’ve done that, have a look at the contents of your project folder. Voila, Git just tracked back your actual project files one commit back! Don’t worry, our work on poem3.txt isn't lost - they're there in Butler Git's personal diary.

What does the HEAD~1 in the checkout command mean though? The term HEAD represents the commit the project currently is at. Since before executing the command our project was at commit "Add poem 3", HEAD would have represented that commit. Then, the ~1 part says "one commit before", so HEAD~1 means "one commit behind the current commit", or in simpler terms, "one commit back" which is what we wanted.

In case you messed up something in the checkout, execute git checkout master to return to the latest commit ("Add poem 3").

You can also checkout directly to a commit, by using the first 7 characters of the commit hash as the commit identifier. So the above checkout can also be done using:

# Checkout a commit directly
git checkout f8dad32

An Inside View

All of our discussions and practicals have only given us a view from the audience seat. To understand Git properly, it’s essential to have a good idea of what goes on behind the scenes when we execute Git commands. We’ll represent our directory along with the Git repository (as it was before, adding poem 3) as follows:

The red pane represents your file system — the actual files you would see in your project directory. The green pane is the staging area — it’s a place inside Git where your staged changes are kept track of. The blue pane shows the butler’s personal diary — it records the current commit you are at, and what that commit contains.

Now let’s add the contents of Poem 3 in a new file. The file system pane would get updated with the new file. Note that since we haven’t staged any changes yet, the staging area would still be empty.

Now, when we staged our changes with git add poem3.txt, Git adds a change to the staging area - that we added a new file called poem3.txt. The staging area would then look like this:

Next, we commit our changes to the repository with git commit -m "Add poem 3". This submits our staged changes (just one, in this case) to the repository in the form of a new commit. So, our staging area gets cleared and the repository gets updated with the new commit:

Finally, let’s try checking out the project one commit back, with git checkout HEAD~1. This asks the repository to track back to one commit earlier, and make changes to our file system so that it matches with the older state of the project:

There, now you know what happens the scene when someone stages changes, makes a commit or checks out past commits. It’s really as simple as that.

Summary

We covered a lot of the fundamentals of Git. In particular, we covered the following commands:

  • git init: Initialises a Git repository in the current directory
  • git status: Displays the current status of the repository
  • git add: Stage the changes of a single file or directory
  • git commit: Commit all staged changes to the repository
  • git checkout: Check out a past version of the project

… and had a good look at the backstage when these commands are executed.

But this is just the tip of the iceberg — Git has a very cool commit tree structure underneath that allows for some useful concepts and features like branching and merging. That’s something we’ll cover in the next part of the series.

--

--