This hands-on exercise walks you through a simple Git workflow.

  1. create a new local Git repo (git init).
  2. create and edit files in the repo.
  3. snapshot files in preparation for versioning, i.e., stage files to the staging area (git add).
  4. record file snapshots in version history, i.e., commit the staged changes (git commit).
  5. go back to 2 and repeat.

Along the above “cycle”, you will also learn a few other things.

Note that all Git commands start with git.

Now, let’s get started by checking what version of git we have.

$ git --version
git version 2.7.4

If it’s the first time you use Git, you will need to configure a few things. At minimum, you should tell git your name and email address.

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

I configured my git at global/user level (hence the --global option). This means the setup applies to all my projects. Other users with different login accounts won’t have my setup.

Display the configuration.

$ git config --global --list
user.name=John Doe
user.email=jdoe@example.com

Check the directory I am currently in (pwd: path to working directory). pwd is a Linux command. Windows users can use the cd command to do the same thing.

$ pwd
/home/jdoe

Create a new directory gitworkshop in the current directory (mkdir: make directory).

mkdir gitworkshop

Enter the gitworkshop directory (cd: change directory).

$ cd gitworkshop

Create a new local Git project.

$ git init

The above command creates a hidden directory .git. This is where Git keeps all the version control information for this project. Let’s use tree .git to list all files in the .git directory in a tree-like format.

$ tree .git
.git
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

A lot of things are already in the .git directory. More will be added along the way we version control our project. Let’s just note that this is where Git keeps its internal data and don’t worry about the details for now.

Create a new file notes.txt, and add a line line 1: git is cool. to it. I’ll use a text editor called nano. You can use your own favorite text editor.

$ nano notes.txt

Check the content of the notes.txt file (cat [file]).

$ cat notes.txt
line1: git is cool.

git status lists all new or modified files to be committed for version control. If we run this command now, it will tell us that the newly created file note.txt is not tracked yet.

$ git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        notes.txt

nothing added to commit but untracked files present (use "git add" to track)

The git status output also shows that we are “On branch master”. This means we are working on the “master” version history line. “master” is a branch reference name. (Git allows you to create new branches and work on different branch lines. We won’t discuss branching in this handout.)

Now, let’s stage all untracked files using the git add . command. The . here tells Git to stage all files in the current directory and sub-directories. Staging is the process of preparing files for version control.

git add .

Now, git status will tell you that the notes.txt file is ready to be committed.

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

        new file:   notes.txt

Commit the changes, i.e. record version history.

git commit -m "initial commit"
[master (root-commit) cff7ab5] initial commit
 1 file changed, 1 insertion(+)
 create mode 100644 notes.txt

The -m option allows you to write a commit message.

git status will tell you “nothing to commit” this time.

$ git status
On branch master
nothing to commit, working directory clean

Check the version history so far.

$ git log
commit cff7ab50f5a9337fb588d584b004f5c8a2e7e39c
Author: John Doe <jdoe@example.com>
Date:   Mon Apr 22 17:45:07 2019 -0400

    initial commit

The git log output shows you who and when the commit is done. The long string starting with cff7a is the commit id that uniquely identifies the commit.

Now, add a new line line2: git is fun. to the notes.txt file.

$ nano notes.txt
$ cat notes.txt
line1: git is cool.
line2: git is fun.

Check git status again. We see that Git knows the file has been modified, but it’s not staged yet.

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   notes.txt

git diff shows differences between tracked files in working directory and those in staging area.

$ git diff
diff --git a/notes.txt b/notes.txt
index 0ba590f..a9fc135 100644
--- a/notes.txt
+++ b/notes.txt
@@ -1 +1,2 @@
 line1: git is cool.
+line2: git is fun.

Create a new file handout.txt, and add a line handout for git intro to it.

$ nano handout.txt
$ cat handout.txt
handout for git intro

This time, git status will show an untracked file handout.txt in addition to the modified tracked file notes.txt.

$ git status
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   notes.txt

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        handout.txt

no changes added to commit (use "git add" and/or "git commit -a")

We could stage and commit both changes at the same time. However, suppose the two changes are not related. In this case, it’s a good practice to commit the two changes separately. Stage and commit the change in notes.txt first.

$ git add notes.txt
$ git commit -m "added line 2 to notes.txt"
[master de81fb9] added line 2 to notes.txt
 1 file changed, 1 insertion(+)

Stage/track the new file handout.txt and commit it.

$ git add handout.txt
$ git commit -m "created handout.txt"
[master 7c0b164] created handout.txt
 1 file changed, 1 insertion(+)
 create mode 100644 handout.txt

Check the commit history so far.

$ git log
commit 7c0b1647007f408e6f40bde09e8942e6711fbedd
Author: John Doe <jdoe@example.com>
Date:   Tue Apr 23 09:38:42 2019 -0400

    created handout.txt

commit de81fb9b9fb014ff71533c0c54af812eb4758c27
Author: John Doe <jdoe@example.com>
Date:   Tue Apr 23 09:37:19 2019 -0400

    added line 2 to notes.txt

commit cff7ab50f5a9337fb588d584b004f5c8a2e7e39c
Author: John Doe <jdoe@example.com>
Date:   Mon Apr 22 17:45:07 2019 -0400

    initial commit

Now, let’s create a GitHub repo gitworkshop and push our project to GitHub (see GitHub Create a Repo for detailed instructions). The repo on GitHub is called remote repo. After creating it, we need to add its information (path) to our local repo.

$ git remote add origin https://github.com/jdoe/gitworkshop.git

origin is the name of the remote repo. You can give it any name, but by convention, people use “origin” for a project’s first remote repo (you can have multiple remote repos for a project). https://github.com/jdoe/gitworkshop.git is the path to remote repo. Within the path, jdoe is the GitHub username. gitworkshop.git is the remote repo on GitHub.

We are ready to push the local repo to remote.

$ git push -u origin master

This pushes your master branch (“your master history line”) to the remote repo origin. The -u option adds a upstream tracking reference. Next time (when you are on master branch), you only need to type git push to push new version history to the remote repo. Git knows it must be the origin/master you are pushing to.

Let’s check the version history again. This time we’ll use --oneline option to make the output concise, and --decorate option to print out reference names.

$ git log --oneline --decorate
7c0b164 (HEAD -> master, origin/master) created handout.txt
de81fb9 added line 2 to notes.txt
cff7ab5 initial commit

We can see we have three commits so far. We are currently (HEAD) at our last commit (ID starting with 7c0b164) on the “master” history line (master branch). This is also where our remote repo’s master branch (origin/master) is.