Skip to content

Git basics

Practical 7.2 git-basics-annex.pdf · PDF

Look at this folder. It belongs to a real student:

practical-7.1.md      practical-7.1-v2.md
practical-7.1-final.md      practical-7.1-final-GOOD.md

Which one was handed in? What changed between v2 and final? If final-GOOD is broken, how do you get Monday's text back? Nobody can answer from the names. Not even the person who wrote them.

Every programmer, every technical writer and every system administrator has this problem. Professionals solve it with one tool, and from today you will too. It is also the tool that will hold your documentation of the Tramuntana office server until the end of the course.

What you will learn

  • What version control solves that report-final-v2.md does not
  • Create a repository with git init and say what the .git folder is
  • Move a change through the three places: working directory, staging area, repository
  • Read git status, git diff and git log and say which question each one answers
  • Keep files out with .gitignore, and why a committed password is never really deleted
  • Throw away an unwanted change with git restore, and write a commit message another person understands

What version control is

Version control is a program that keeps the history of a folder: every saved state, who saved it, when and why.

The folder together with its history is called a repository (or "repo"). The program you will use is Git, by far the most used version control system today.

The photo album (we keep it all page)

Your folder is a room where you work, and things move around all the time. When the room is in a state worth remembering, you take a photo and write on the back what it shows. The album is the history.

Each photo is a commit: a snapshot of all the files, plus a message, the author, the date and a unique identifier. You can look at any old photo and put the room back exactly as it was.

Folder of copies Git repository
final, final-v2, final-GOOD: names you invent Every version has a message that says what changed
No idea who changed what Every commit records its author and date
Getting Monday's text back means guessing Any commit can be shown or restored
Many copies of the same file waste space One folder; the history lives in .git

A story: ten days in April 2005

The Linux kernel — written by thousands of developers — used a proprietary version control tool, BitKeeper, free of charge. In 2005 the company withdrew that free use. Linus Torvalds, the creator of Linux, started writing a replacement on 3 April 2005. He announced it on the 6th, and on the 7th Git was already storing its own source code. Linux 2.6.12, released on 17 June 2005, was the first kernel managed with Git. On 26 July Torvalds handed the project to Junio Hamano, who still maintains it.

The name is a joke: Torvalds said he names his projects after himself, and "git" is British slang for an unpleasant person.

Remember Software by licence and purpose: a proprietary tool changed its conditions, and a community wrote its own. Git is free software, licensed under the GPL-2.

Careful: Git is not GitHub

Git is the program on your machine. It works with no network at all — everything on this page happens offline. GitHub, GitLab or Forgejo are websites that host a copy of a repository. That is the next page.

Your first repository

First install Git and introduce yourself. Every commit is signed with this name and e-mail, so use your school address: it will be visible to anyone who can see the repository.

sudo apt update && sudo apt install -y git
git config --global user.name "Your Name"
git config --global user.email "your school e-mail"
git config --global init.defaultBranch main
git config --global --list

The last command prints your three settings. The third line names the first branch main (a branch is a line of commits — more about it on the next page).

Now create the folder and turn it into a repository:

mkdir ~/tramuntana-docs
cd ~/tramuntana-docs
git init
ls -a
git status
$ git init
Initialized empty Git repository in /home/marta/tramuntana-docs/.git/
$ git status
On branch main

No commits yet

nothing to commit (create/copy files and use "git add" to track)

ls -a shows a new hidden folder: .git. That is the album. The whole history lives there, inside your project folder.

Careful: git init in the right folder

If you type git init in your home directory instead of inside tramuntana-docs, your whole home becomes a repository. Run pwd first. If it happened, remove the wrong album with rm -rf ~/.git — and check the path twice before pressing Enter.

The first commit

Create README.md with a title and one sentence. Then:

git status
git add README.md
git status
git commit -m "Add README with project summary"
git log

Before git add, git status calls the file untracked: Git sees it, but does not follow it yet. After git add it appears under Changes to be committed. Then the commit:

$ git commit -m "Add README with project summary"
[main (root-commit) bd8efc6] Add README with project summary
 1 file changed, 3 insertions(+)
 create mode 100644 README.md

bd8efc6 is the start of the commit's identifier. Yours will be different — every commit in the world has its own. git log shows the full identifier, the author and the date.

Problem Cause Fix
Author identity unknown You skipped git config Run the user.name and user.email lines
A long hint about master init.defaultBranch main is missing git branch -m main
An editor opens after git commit You forgot -m "message" Write the message on the first line, then Ctrl+O, Enter, Ctrl+X (nano)

The three places

Why do you need two commands, add and commit, to save one change? Because Git has three places, and a change travels from left to right:

flowchart LR
    WD["<b>Working directory</b><br>your files as they are now<br>(the room)"] -->|"git add"| ST["<b>Staging area</b><br>what goes in the next commit<br>(in front of the camera)"]
    ST -->|"git commit"| REPO["<b>Repository</b><br>all the commits, in .git<br>(the album)"]
    REPO -->|"git restore"| WD
  • The working directory is your folder, as it is right now.
  • The staging area is what you have placed in front of the camera for the next photo.
  • The repository is the album: all the commits, stored in .git.

Often you change five things and want two separate photos: "fix the address" and "add the backup section". git add chooses what enters each photo.

Careful: saving is not committing

Pressing Ctrl+S in your editor changes the room. The photo is only taken by git commit. And git add stages a file as it is now: change it again after add, and you must add again.

Three commands, three questions

Command The question it answers
git status Where is each file right now: untracked, modified, staged?
git diff What exactly changed in the working directory, line by line, that is not staged yet?
git diff --staged What exactly will enter the next commit?
git log --oneline Which photos are in the album, newest first?

Add a line to README.md and run git diff:

$ git diff
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
 # Tramuntana office server

 Documentation of the office server of Tramuntana Apps (Palma).
+
+Server: `ubu-srv`, Ubuntu Server 26.04 LTS.

Lines starting with + were added. Lines starting with - were removed. The rest is context, so you can see where the change is.

git status --short shows one letter per file: M means modified, ?? means untracked. Now the surprise: run git add README.md and then git diff again. It prints nothing. Plain git diff compares the working directory with the staging area, and after add they are equal. The change has moved one box to the right: git diff --staged shows it.

When you create a new folder, git status shows only the folder (docs/), not the files inside. Git lists a new folder as one line until you add it.

A good commit message

Bad: changes, asdf, update. They say nothing to the person reading the album in a year — probably you.

Good: a short order in the present tense that says what the commit does: Add overview page, Fix server address, Describe the server in the README. The Git manual recommends a first line of no more than 50 characters. And one idea per commit: two different changes deserve two photos.

What must stay out of the album

Ask yourself: what is in this folder that nobody else should get? Three kinds of file never go in a repository:

Kind Examples Why
Secrets Passwords, private SSH keys, tokens Anyone with a copy of the repository can read them
Things you can build again The PDF generated from your Markdown, temporary files They are a product, not a source
Big binaries that change often ISO images, virtual disks Every version is stored for ever and the album explodes

.gitignore is a file listing the names and patterns that Git must act as if it did not see.

One pattern per line: build/ (a whole folder), *~ (editor backup files), passwords.txt (one file). Try it:

mkdir build
touch build/test.pdf
echo "password: 1234" > passwords.txt
git status
$ git status
On branch main
Untracked files:
    build/
    passwords.txt

Now create .gitignore with the two lines build/ and passwords.txt, and run git status again: only .gitignore is listed. The two names have disappeared from Git's sight. Now it is safe to git add . (the dot means "everything here") and commit.

A committed password is never deleted

"I committed the password, then I deleted the file and committed again: it's gone." It is not. The old photo is still in the album, and anyone with the repository can open it. Once a secret is committed, the only safe fix is to change the password. So the order is always: .gitignore first, git add after.

Also careful: .gitignore only affects untracked files. A file that is already committed stays tracked even if you add its name later.

Undoing a change

The album protects you. Break a file on purpose:

echo "oops" > README.md
git diff --stat
git restore README.md
cat README.md

git restore README.md throws away the changes in the working directory and puts back the version of the last commit. git status then says nothing to commit, working tree clean.

Be clear about what that means: the changes you restored were never committed, so they are gone for good. That is exactly what you asked for.

If you staged something by mistake (for example, passwords.txt before writing .gitignore), git restore --staged passwords.txt takes it back out of the staging area without touching the file.

Reading the album

git log --oneline
git show --stat HEAD
d73894c Add overview page and ignore build output
20cf579 Describe the server in the README
bd8efc6 Add README with project summary

Newest first. HEAD is Git's name for the commit you are standing on — the last photo. git show --stat HEAD lists the files that commit changed.

A commit is a full snapshot

It is tempting to think a commit stores only "the difference from the last one". Think of it as a full photo of the project instead. When Git shows you a difference, it is comparing two photos.

In Practical 7.2 (the button at the top) you build this repository step by step and then fill docs/01-overview.md with the real data of your ubu-srv: one idea, one commit. Keep the folder ~/tramuntana-docs: it becomes the assessed documentation of the unit.

Key takeaways

  • Version control keeps the history of a folder; the folder plus its history is a repository, and Git stores it in the hidden .git folder.
  • A commit is a snapshot of the whole project with a message, an author, a date and an identifier — a photo in the album.
  • A change travels working directory → (git add) → staging area → (git commit) → repository.
  • git status says where each file is, git diff shows unstaged changes line by line, git diff --staged shows what will be committed, git log shows the history.
  • .gitignore keeps secrets, build output and big binaries out; a password that was ever committed must be changed.
  • git restore discards uncommitted changes; Git works offline and is not the same thing as GitHub.

Quick check

1. What is a commit?
  • A snapshot of the whole project, with a message, author and date
  • The last saved version of one single file
  • A copy of the project folder on a website
  • A list of the files Git must ignore

A commit is a photo of the whole project at one moment, with a message saying what it shows, the author, the date and a unique identifier. Saving a file is not a commit, and a website copy is a remote, which comes on the next page.

2. Which command chooses what will go into the next commit?
  • git add
  • git status
  • git log
  • git init

git add moves a change from the working directory to the staging area: it places it in front of the camera. git status only reports, git log reads the history and git init creates the repository.

3. You edit README.md, run git add README.md, and then run plain git diff. What does it print?
  • Nothing, because the change is already staged
  • The lines you added, marked with a plus sign
  • The full content of the last commit
  • An error, because the file was already added

Plain git diff compares the working directory with the staging area. After git add they are identical, so it prints nothing. The change is now visible with git diff --staged.

4. A classmate committed a file with the server password, deleted it and committed again. What makes it safe?
  • Changing the password
  • Adding the file name to .gitignore
  • Running git restore on the file
  • Making one more commit without the file

The old commit still contains the file, and anyone with the repository can open it. .gitignore only affects untracked files, and new commits do not change old ones. The only safe fix is to change the password.

5. What does git restore notes.md do?
  • Discards the uncommitted changes to notes.md
  • Deletes notes.md from the whole history
  • Undoes the last commit of the project
  • Uploads notes.md to the remote copy

git restore puts back the version of the last commit in the working directory. The changes it throws away were never committed, so they are lost — which is what you asked for.

6. Where does the whole history of a Git repository live?
  • In the hidden .git folder inside the project
  • On the GitHub servers
  • In the staging area
  • In the .gitignore file

Every commit is stored in the .git folder that git init creates. Git works fully offline; a website such as GitHub only hosts an extra copy if you push one there.

7. Your project folder contains report.md, build/report.pdf (generated by a script) and a private SSH key. Select the two that should be listed in .gitignore.
  • build/
  • The private SSH key
  • report.md
  • .gitignore itself

Build output can be generated again from the sources, and a secret must never enter the album. report.md is the real source of your work, and .gitignore itself is committed so that everyone shares the same rules.

Next: today the album lives in one laptop — if the disk dies, the history dies. Give it a second home and a second author in Git remotes and collaboration.