Menu for Per-Arne's Git Good!
Courses and project Per-Arne's Git Good!

What is Git? Snapshots and your first commit

Module 1: Foundations · 10 min

The interactive lesson needs JavaScript. The text below is the complete lesson.

After this lesson you can

  • explain what a commit is, and how parent links connect commits into history understand
  • turn a folder into a repository with git init, make a commit with git add and git commit, and see it with git log apply

Understand: A project with a memory

Have you ever had files called report-final, report-final-2 and report-final-really? Git solves that problem. Git remembers what your project looked like at chosen moments, so you can safely go back, compare and collaborate.

Each such moment is called a commit. A commit is a complete snapshot of every file Git tracks, not just what changed. It also has a message, an author and a time.

When you commit again, the new commit gets a pointer to its parent. That makes history a chain of snapshots.

Notice the direction: arrows point back in time. A commit knows its parents but never its children, because they did not exist when it was made.

The name main is a branch: a label that points to the latest commit on this line of work and moves when you commit on it.

The whole history lives in a hidden folder, .git, inside the project. The project folder with this history is called a repository. Git needs neither the internet nor GitHub to work.

Watch: Your first repository

We are in an empty folder. git init turns it into a repository. The graph is still empty: no commits yet.

$ git init

Now we create a file. It appears in the working tree: the files you see and edit.

$ echo "Hello, Git!" > README.md

Before we continue: what do you think git status says about the file?

$ git status

git add puts a copy of exactly this version in the staging area, also called the index: the draft of the next commit. Notice that the card now also sits in the staging area. The file will be part of the next snapshot.

$ git add README.md

Now we take the snapshot. The message says briefly what the commit does. Look: a commit appears in the graph, and main points to it.

$ git commit -m "Add welcome text"

Finally we read the history. The short code is the start of the commit's ID. Git computes it from the whole commit: content, parent, message, author and time. That is why it is unique in practice.

$ git log --oneline

Tasks

  1. Turn the folder into a Git repository.
  2. Create the file README.md with some text in it.
  3. Ask Git for the status of the folder.
  4. Stage README.md for the next commit.
  5. Make a commit with a descriptive message.
  6. Show the history with one line per commit.

Practise: Transfer: two more commits

A new repository with one commit. No demo this time — use what you just saw.

Tasks

  1. Change README.md and save the change in a new commit.
  2. Create a new file notes.txt and commit it in a commit of its own.

Check yourself: Recall it

What does a commit store?

  • Only the lines changed since the previous commit
  • A snapshot of the tracked files, plus message, author and parent
  • A link to the files in the folder, so later edits are included automatically

Where does Git store the commits you make in a repository?

  • On GitHub
  • In the .git folder inside the project
  • In one shared Git database for the whole computer

Why do arrows point from a new commit to its parent, and not the other way?

  • A commit cannot change after it is made, and its children did not exist when it was made
  • It is just a drawing convention
  • Because Git reads history from the oldest commit forwards

Common misconceptions

  • “Git and GitHub are the same.” Git is the program that stores history locally. GitHub is one of several services that can host a copy.
  • “A commit stores only the changes.” It points to a complete snapshot; changes are computed when you ask for them.

Read more

Git, repositories and hosting

  • Git is a program on your own machine. It stores a project's history as a chain of commits.
  • A repository is the project folder plus the hidden .git folder, where Git keeps objects (file content, snapshots, commits) and references such as main and HEAD.
  • GitHub, GitLab and Codeberg are hosting services. They keep a copy of the repository and add things Git itself does not have: pull requests, issues, access control and web pages. A pull request is a feature of the service, not of Git.
  • Everything in this lesson is local. git init, git add, git commit and git log work without a network. Only commands that talk to another repository, such as git push, git fetch and git clone, transfer objects and move references somewhere else.

What git init does

$ git init -b main
Initialized empty Git repository in /home/student/project/.git/
  • The command creates .git in the folder you are in. Your files are not touched.
  • -b main chooses the name of the first branch. main is a common convention, not a requirement. Without -b, Git uses the init.defaultBranch setting, and older setups give master.
  • A new repository has a branch without commits. HEAD points to the name main, but main does not point to anything yet. That is why git log fails until you make the first commit:
$ git log
fatal: your current branch 'main' does not have any commits yet
  • Do not edit files inside .git by hand. Delete .git and the whole history is gone, while the files in the folder remain.

Be careful where you run git init. Run it in your home folder by accident and everything below it becomes one big repository. git status always tells you whether you are inside a repository or not.

Who is the author?

Every commit stores a name and an email. Git reads them from the settings. If they are missing, Git tries to guess them from your user name and machine name, and refuses to commit if it cannot:

$ git commit -m "Add welcome text"
Author identity unknown
*** 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.

A guessed name is rarely right, so set both yourself before your first commit:

git config --global user.name "Kari Nordmann"
git config --global user.email "kari@example.com"
  • --global applies to every repository for your user. Without --global, the setting applies only to the repository you are in.
  • The name and email are just text in the commit. They are not a login. When you later push to a server, you sign in with an SSH key or a token through a credential helper.

From file to commit, with real output

A new file is untracked until you run git add on it:

$ echo "Hello, Git!" > README.md
$ git status
On branch main
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    README.md
nothing added to commit but untracked files present (use "git add" to track)

After git add, the file is listed under "Changes to be committed":

$ git add README.md
$ git status
On branch main
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   README.md

The commit itself answers with a short receipt:

$ git commit -m "Add welcome text"
[main (root-commit) ae07153] Add welcome text
 1 file changed, 1 insertion(+)
 create mode 100644 README.md
  • main is the branch that moved. root-commit means this is the first commit, with no parent.
  • ae07153 is the start of the commit's ID. Yours will differ, because the time and the author are part of it.
  • create mode 100644 means the file is new and an ordinary, non-executable file.

git log without options shows the full ID, author, date and message:

$ git log
commit ae07153176166626ac1264449d3bf293f131d342
Author: Student <student@example.invalid>
Date:   Tue Oct 13 09:10:27 2026 +0200
    Add welcome text

In a normal terminal, git log opens a pager when the output is long. Press q to quit.

Snapshots, not lists of changes

  • A commit points to a complete snapshot of every tracked file, plus the message, author, time and the ID of its parent.
  • Files that did not change are not stored again. The new snapshot points to the same content as before. The history lesson shows this with real objects.
  • Diffs are not stored. When you ask for a diff, Git computes it by comparing two snapshots. To save space, Git eventually packs similar objects together in so-called packfiles, where some are stored as differences against others. That is a storage detail you never see. The model you work with is still whole snapshots.
  • The ID is a forty-character hash computed from the whole commit. Repositories that use the newer SHA-256 format have 64-character IDs. Change the content, the message or the parent and you get a new ID. That is why a commit cannot be changed afterwards. Commands that "change history" really make new commits.

Common messages and what they mean

Message Meaning Do this
fatal: not a git repository (or any of the parent directories): .git You are not inside a repository Go to the project folder, or run git init
nothing added to commit but untracked files present Nothing is staged Run git add on the files to include
nothing to commit, working tree clean No changes to tracked files are waiting to be committed Nothing, every change is committed
Author identity unknown Name or email is missing Set user.name and user.email with git config
does not have any commits yet You ran git log before the first commit Make a commit first

Further reading