(Previously: Part 0 – Introduction)

Initializing a local repository

The git init command sets up a local repository in the current folder:

$ cd ~/Projects/cow_tipper
$ git init
Reinitialized existing Git repository in /home/buster/Projects/cow_tipper/.git/

Change history is stored in a .git sub-directory.

Tracking changes, Staging and Committing

Tracked source files

A tracked source file is one that is understood by Git to require a change history to be saved in the repository. Our source directory may contain “tracked” and “untracked” files. We won’t be able to recover change history for an untracked file.


A commit saves a set of source file changes as a “snapshot” that can be recovered later. Commits are sequential, and have a pointer to their parent snapshot. A text message is saved along with the commit.


Staging is the process of adding a file to the set of changes that will be included in the next commit operation.

Now I need to stage my source files for the first commit:

$ git add README.md
$ git add cow_tipper.py

The add command does two things:

  • It marks a file as “tracked”;
  • It copies the file into a staging area

Alternatively, I could just add all the files in the directory in one go:

$ git add *

At this point, all files in the folder are “tracked” and ready to be committed. We can double-check where we are at any time by asking Git using the git status command:

$ git status
On branch master 
Changes to be committed: (use "git restore --staged <file>" to unstage)
   new file: README.md 
   new file: cow_tipper.py

Nice. Let’s save this (“commit” it) to a recoverable snapshot. We’ll use the -m switch to supply a text message directly on the command-line:

$ git commit -m "First Commit"
* * * Please tell me who you are.
Run   git config --global user.email "you@example.com"
      git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address

Oops! Of course Git needs to know who we are, and even tells us what commands we need to run to do this:

$ git config --global user.email "buster@spacefold.com"
$ git config --global user.name "Buster Kitten"

Now let’s re-try that commit:

$ git commit -m "First commit"
[master c9b7b58] First commit
 2 files changed, 8 insertions(+)
 create mode 100644 README.md
 create mode 100644 cow_tipper.py

Success! Note that we don’t have to use the -m “message” command-line switch. If we just git commit then the default text editor will be launched so that we can edit the message. We can customize what editor is used in the configuration: See Appendix B: Customizing the Message Editor.

If we’re really in a hurry we can Stage+Commit in one command:

$ git commit -a

Speaking of configuration parameters, at any time we can ask Git to show us the configuration it’s working with, using git config:

$ git config --list --show-origin
file:/home/buster/.gitconfig     user.email=buster@spacefold.com
file:/home/buster/.gitconfig     user.name=Buster Kitten
file:.git/config        core.repositoryformatversion=0
file:.git/config        core.filemode=true
file:.git/config        core.bare=false
file:.git/config        core.logallrefupdates=true

Read more about Git configuration here: https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration.

The Git Log

Note that each commit gets an identifying hash value assigned to it. We can see the first 7 characters “c9b7b58” in that commit message output above.

The command git log will list recent commits along with their hash, author, date, and comment. The format of the output is very controllable, for example:

$ git log --pretty=format:"%h - %an, %ar : %s"
e875278 - Buster Kitten, 36 minutes ago : trialling the secondary pump control block
82c55cb - Buster Kitten, 14 hours ago : Working on the next problem.
fc5fea3 - Buster Kitten, 22 hours ago : I just added a line for test purposes.
aaee8e5 - Buster Kitten, 24 hours ago : Removing files we don't need.
c9b7b58 - Buster Kitten, 3 days ago : First commit

I’m not going to go into depth about the Git log, so for further reading I recommend: Git Basics – Viewing the Commit History (The Git Book)

(I’ve also written about git log before: Obtaining a useful log of recent check-ins.)


One important feature of a source control system is to retrieve a known snapshot from the change history. Although we can use the unique hash identifier to retrieve a specific snapshot from the repository, it is easier if we use a Tag to mark important points in the history.

Tags are named pointers to specific commit points in the repository change history. We can retrieve a copy of your tracked source files as they were at the time the tag was created. Typically tags are used to mark release points in a development process, such as “Beta 1”, “Beta 2”, “version 0.0.7”, etc.

Creating a tag

We use the git tag command to label the most recent commit:

$ git tag v.0.0.0

Or if we like, we can create an “annotated” tag complete with a text message:

$ git tag -a v.0.0.0 -m "This is the initial state of my source code"

For more on tagging, see https://git-scm.com/book/en/v2/Git-Basics-Tagging

How do I…?

Protect files from being tracked (e.g. .log or .bak files)

git add * is very convenient but if we want to prevent some files from being included in that broad scope, we can leverage the .gitignore file.
See https://www.atlassian.com/git/tutorials/saving-changes/gitignore

Change a tracked file name

The mv command both renames a file in the file system and stages the change for the next commit:

$ git mv <old> <new>

Delete a tracked file

The rm command stages a file for removal, and also deletes the file in the file system:

$ git rm <file>

Unstage a file added incorrectly

To unstage a file, either of these commands work. “restore –staged” is the new way:

$ git reset HEAD <file>
$ git restore --staged <file>

Or just unstage everything staged so far:

$ git reset

Replace a staged file with a more up-to-date version

If you make a second edit to a file after you’ve already staged it, just stage it again to replaced the staged copy:

$ git add <file>

Revert just one file

To discard changes in the working directory, either of these commands work:

$ git checkout -- <file>
$ git restore <file> 

Delete multiple files using a wildcard spec

This command removes files from staging, and also escapes the wildcard character, which is necessary:

$ git rm --cached \*.log

Find out what tags I have

$ git tag

Next up, Part 2: Branching.