Why this matters
Every team that writes software needs to answer three questions all day long: what changed, who changed it, and can we go back? Without a tool, people answer them with folders named app-final, app-final-2, and app-really-final, and with a chat history that nobody can reconstruct. A version control system answers those questions properly. It records the exact content of your files at each point you choose, remembers who recorded it and why, and lets you compare or return to any of those points.
Git is the version control system almost the entire industry uses. It is not tied to any website: a Git repository is just a hidden .git directory inside your project that holds the complete history. GitHub and GitLab are hosting products built *around* Git, but you can do real work — commits, branches, merges, history — with nothing but the git command on your own machine. That is exactly how this course starts. You will build one small HTTP service on your lab machine linux01 and carry it all the way to a released, containerised application. This first lesson gets the service under version control.
By the end you will have a repository with four commits, a running Python service, and a clear mental model of the three places your work lives before it becomes permanent history.
Concepts
A repository is a project directory plus the .git folder that stores its history. You create one with git init. Nothing leaves your machine.
A commit is a snapshot: the exact content of the tracked files at the moment you record it, plus a message, an author, and a link to the commit before it. Commits are the units of history. Each has a unique 40-character hash (for example f48ab710…); the first seven characters are usually enough to name it.
Git has three areas, and understanding them removes most early confusion:
- The working tree is the files as they exist on disk right now — what you edit.
- The staging area (also called the *index*) is a holding area where you assemble exactly what your next commit will contain.
- The repository is the permanent history of commits.
You move a change from the working tree to the staging area with git add, and from the staging area into history with git commit. This two-step design is deliberate: it lets you commit *some* of your changes and leave others for later.
git status tells you where everything sits — untracked, modified, staged. git diff shows the actual line-by-line changes: with no arguments it shows working-tree changes not yet staged; with --staged it shows what you have staged for the next commit. git log shows the history.
A `.gitignore` file lists paths Git should not track — generated files, caches, secrets. Ignoring a file keeps it out of history and out of git status noise.
Guided exercise
Open a terminal on your lab machine linux01. Confirm the tools and versions:
head -2 /etc/os-release
git --version
python3 --version
whoamiPRETTY_NAME="Ubuntu 24.04.4 LTS"
NAME="Ubuntu"
git version 2.43.0
Python 3.12.3
ubuntu1. Identify yourself. Git stamps every commit with a name and email. Set them once:
git config --global user.name "Ada Learner"
git config --global user.email "ada.learner@example.com"
git config --global init.defaultBranch mainUse your own name and a contact email; the address is a label on your commits, not a login. init.defaultBranch main makes new repositories start on a branch called main.
2. Create the repository.
mkdir -p ~/app
cd ~/app
git initInitialized empty Git repository in /home/ubuntu/app/.git/3. Make the first commit. Create a README, then watch it move through the three areas:
cat > README.md <<'EOF'
# app
A small HTTP status service used throughout this course.
EOF
git status
git add README.md
git commit -m "Add README"git status first calls README.md an *untracked* file. After git add it is a *change to be committed* (staged). After git commit it is history:
[main (root-commit) f48ab71] Add README
1 file changed, 3 insertions(+)
create mode 100644 README.md4. Add the service and commit it.
mkdir -p service
cat > service/server.py <<'EOF'
"""A tiny HTTP service. GET / returns a plain-text greeting."""
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = b"app is running\n"
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
if __name__ == "__main__":
ThreadingHTTPServer(("0.0.0.0", 8080), Handler).serve_forever()
EOF
git add service/server.py
git commit -m "Add minimal HTTP service"Confirm the service actually runs, then stop it:
python3 service/server.py >/tmp/server.log 2>&1 & echo $! >/tmp/server.pid; sleep 1
curl -s http://127.0.0.1:8080/
kill "$(cat /tmp/server.pid)"app is running5. See the difference between the working tree and the staging area. Add run instructions to the README, then inspect:
printf "\n## Run it\n\n python3 service/server.py\n" >> README.md
git diff
git add README.md
git diff
git diff --staged
git commit -m "Document how to run the service"The first git diff shows your change with + lines. After git add, git diff shows *nothing* — because it reports the working tree against the staging area, and they now match. git diff --staged shows the change, because it compares the staging area against the last commit. This is the single most useful thing to internalise: `git diff` is unstaged changes, `git diff --staged` is what you are about to commit.
6. Ignore generated files. Running Python created a __pycache__ directory. It is build output, not source, so it should never be committed:
python3 -m py_compile service/server.py
git status
cat > .gitignore <<'EOF'
__pycache__/
*.pyc
.venv/
.env
EOF
git check-ignore -v service/__pycache__/server.cpython-312.pyc
git add .gitignore
git commit -m "Ignore Python caches and local environment files"git check-ignore -v proves *which* rule matches a path:
.gitignore:1:__pycache__/ service/__pycache__/server.cpython-312.pycNote that .env is ignored from the start; you will store secrets there later, and they must never enter history.
Review your work:
git log --oneline
git log --oneline | wc -l986ae57 Ignore Python caches and local environment files
380a6e7 Document how to run the service
e582e06 Add minimal HTTP service
f48ab71 Add README
4Troubleshooting
Symptom → Author identity unknown when you commit. Cause: user.name/user.email are unset. Fix: run the two git config --global commands in step 1; the email is a label, so any address you own is fine.
Symptom → nothing to commit, working tree clean but you just edited a file. Cause: you edited a file that is ignored, or you edited it in a different directory. Fix: run git status; if the file is missing from the output, check git check-ignore -v FILE.
Symptom → you committed __pycache__ before adding .gitignore. Cause: .gitignore only stops *untracked* files from being added; it does not remove already-tracked ones. Fix: git rm -r --cached service/__pycache__ then commit; the files stay on disk but leave history going forward.
Symptom → git commit opens an editor you do not know how to exit. Cause: you ran git commit without -m. Fix: in the default editor nano, save with <kbd>Ctrl</kbd>+<kbd>O</kbd> then exit with <kbd>Ctrl</kbd>+<kbd>X</kbd>; next time pass -m "message".
Symptom → curl: (7) Failed to connect. Cause: the server is not running, or exited. Fix: check /tmp/server.log; a SyntaxError there means the file has a typo — fix it and rerun.
Check your understanding
Take the Chapter 1 quiz after lesson 4. Meanwhile, confirm you can answer these:
What is the difference between git add and git commit?
git add copies the current content of a file into the staging area, choosing what the next commit will contain. git commit records everything staged as a permanent snapshot with a message. You can add several times before one commit.
You edited two files but want to commit only one. How?
git add only the file you want, then git commit. git status and git diff --staged confirm exactly what is going in before you commit.
Summary and next step
- A Git repository records snapshots (commits) of your project on your own machine; no account is needed.
- Changes flow working tree → staging area (
git add) → repository (git commit);git statusandgit diff/git diff --stagedshow you where things are. .gitignorekeeps generated files and secrets out of history.
Next, in lesson 2, you will branch to develop a feature in isolation, merge it back, and resolve a merge conflict by hand.
References
- Git — Getting Started and Basics (Pro Git) — https://git-scm.com/book/en/v2 (accessed 2026-09-13)
- git-scm.com — git status — https://git-scm.com/docs/git-status (accessed 2026-09-13)
- git-scm.com — gitignore — https://git-scm.com/docs/gitignore (accessed 2026-09-13)
- Python 3.12 — http.server — https://docs.python.org/3.12/library/http.server.html (accessed 2026-09-13)
Sign in to record your progress
Signing in saves eligible progress. It does not enroll you or include a lab; review the career path for access terms.