🌿

Git & Version Control Beginner

Track and collaborate on code with Git: commits, branches, merges, remotes, conflicts and team workflows.

18 lessons 54 quiz questions
Lessons & quizzes Certificate

📚 Lessons & quizzes

Each lesson ends with its own short quiz. Answer them as you go — score 90% across all lessons to earn your certificate.

1 What Is Version Control and Why Use It?

A version control system (VCS) records changes to a set of files over time so you can recall any earlier version, see who changed what, and work together without overwriting each other’s work. Without it, teams resort to fragile habits like emailing zip files or keeping folders named project_final_v2_REALLY_final.

  • History — every change is saved, so you can roll back a mistake.
  • Collaboration — many people edit the same project safely.
  • Accountability — each change is attributed to an author and a reason.
  • Branching — you can try ideas in isolation, then merge what works.

Git is by far the most popular VCS today. It powers platforms such as GitHub, GitLab and Bitbucket.

# Check your installed Git version
git --version

2 Centralised vs Distributed Version Control

Older systems like Subversion (SVN) are centralised: there is a single central server holding the history, and clients check out a working copy. If the server is down, you cannot commit.

Git is distributed: every clone is a full copy of the entire repository, including its complete history. This means:

  • You can commit, branch, and view history offline.
  • There is no single point of failure — every clone is a backup.
  • Most operations are fast because they happen locally, not over the network.

A “central” repository (like one on GitHub) is just a convention — technically every clone is equal.

# Cloning copies the FULL history to your machine
git clone https://github.com/example/project.git

3 Starting a Repository: git init and git clone

There are two ways to get a Git repository on your machine.

  • git init turns an existing folder into a brand-new, empty repository. Git creates a hidden .git directory that stores all history and metadata.
  • git clone downloads an existing repository (and its full history) from a remote URL.

Before your first commit you should also tell Git who you are, because every commit records an author name and email.

# Create a new repo in the current folder
git init

# Identify yourself (once, globally)
git config --global user.name "Ada Lovelace"
git config --global user.email "ada@example.com"

4 The Three Areas: Working Directory, Staging, Repository

Git organises your work into three conceptual areas:

  1. Working directory — the actual files you see and edit on disk.
  2. Staging area (also called the index) — a snapshot of what will go into the next commit. You move changes here with git add.
  3. Repository (the .git database) — where committed snapshots live permanently.

The flow is: edit files (working directory) → git add (staging) → git commit (repository). The staging area lets you craft a commit from some of your changes rather than all of them.

# See which files are in which area
git status

5 Recording Changes: git add and git commit

git add stages changes; git commit permanently records the staged snapshot in the repository together with a message. Each commit gets a unique SHA-1 hash identifier and points to its parent commit, forming a history.

A good commit is a small, logical unit of change. You can stage a single file, several files, or everything that changed.

The -m flag supplies the commit message inline. Omitting it opens your text editor instead.

# Stage one file, then everything, then commit
git add README.md
git add .
git commit -m "Add project README and initial files"

6 Viewing History: log, diff and show

Git gives you several lenses on your project’s past:

  • git log lists commits, newest first, with author, date and message. --oneline condenses each to a single line.
  • git diff shows line-by-line changes. With no arguments it shows unstaged changes; --staged shows what is staged.
  • git show displays a single commit: its metadata and the exact changes it introduced.
# Compact history graph
git log --oneline --graph

# What have I changed but not staged yet?
git diff

# Inspect one commit in detail
git show a1b2c3d

7 Branches: Create and Switch

A branch is simply a movable pointer to a commit. The default branch is usually called main (older repos use master). Creating a branch is cheap and instant because Git only writes a tiny pointer.

Branches let you develop a feature in isolation without disturbing main. The modern command git switch changes branches; git switch -c creates and switches in one step. (The older git checkout -b does the same.)

# Create and switch to a new branch
git switch -c feature/login

# List branches and switch back to main
git branch
git switch main

8 Merging: Fast-Forward vs Three-Way

Merging integrates the changes from one branch into another. There are two main cases:

  • Fast-forward — if the target branch has not moved since the feature branch started, Git simply slides the pointer forward. No new commit is created.
  • Three-way merge — if both branches have new commits, Git combines them using their common ancestor and creates a special merge commit with two parents.

You merge into your current branch, so switch to the destination first.

# Bring feature/login into main
git switch main
git merge feature/login

9 Merge Conflicts and How to Resolve Them

A merge conflict happens when two branches change the same lines of the same file in incompatible ways. Git cannot decide automatically, so it pauses and marks the conflict inside the file with markers:

<<<<<<< HEAD
your version
=======
their version
>>>>>>> feature/login

To resolve: edit the file to the desired final result, remove the marker lines, then git add the file to mark it resolved, and git commit to finish the merge.

# After editing the file to fix the conflict:
git add conflicted-file.txt
git commit

10 Rebase vs Merge and the Golden Rule

git rebase moves your branch’s commits so they start from the tip of another branch, rewriting them as new commits. The result is a clean, linear history with no merge commits. git merge instead preserves the exact history and adds a merge commit.

The golden rule of rebase: never rebase commits that you have already pushed and that others may have based work on. Rebasing rewrites history (commits get new hashes), which breaks shared branches. Rebase only your own local, unpushed work.

# Replay current branch on top of the latest main
git switch feature/login
git rebase main

11 Remotes: origin, fetch, pull and push

A remote is a version of your repository hosted elsewhere (e.g. on GitHub). The default remote name is origin. Key commands:

  • git fetch downloads new commits from the remote but does not change your working branch.
  • git pull fetches and then merges (or rebases) those changes into your current branch.
  • git push uploads your local commits to the remote.

So pull = fetch + merge. Use fetch when you want to inspect changes before integrating them.

# Send local commits up, bring remote commits down
git push origin main
git fetch origin
git pull origin main

12 Ignoring Files with .gitignore

Not everything belongs in version control: build artefacts, dependency folders, secrets and OS junk should stay out. A .gitignore file lists patterns of files Git should not track.

  • Each line is a pattern, e.g. node_modules/ or *.log.
  • A leading # marks a comment; a trailing / matches directories.

Important: .gitignore only affects untracked files. A file Git is already tracking keeps being tracked even if you add it to .gitignore — you must untrack it explicitly.

# Create ignore rules, then stop tracking an already-committed file
printf 'node_modules/\n*.log\n.env\n' > .gitignore
git rm --cached secrets.env

13 Tags and Releases

A tag marks a specific commit with a permanent, human-friendly name — typically a release version like v1.0.0. Unlike branches, tags do not move.

  • Lightweight tags are just a name pointing at a commit.
  • Annotated tags (created with -a) store extra metadata: tagger, date and a message. These are preferred for releases.

Tags are not pushed automatically; you push them explicitly. Many platforms turn a pushed tag into a downloadable release.

# Create an annotated release tag and push it
git tag -a v1.0.0 -m "First stable release"
git push origin v1.0.0

14 Undoing Changes: restore, reset and revert

Git offers several ways to undo, and they differ importantly:

  • git restore (or older git checkout -- file) discards uncommitted changes in your working files.
  • git reset moves the branch pointer to an earlier commit. --soft keeps changes staged; --mixed (default) keeps them unstaged; --hard discards them entirely (dangerous).
  • git revert creates a new commit that undoes a previous one, without erasing history. This is the safe choice for shared branches.

Rule of thumb: revert public history, reset only your private, unshared commits.

# Discard local edits to a file
git restore app.js

# Undo a pushed commit safely (new inverse commit)
git revert a1b2c3d

# Move branch back, keeping changes staged
git reset --soft HEAD~1

15 Stashing Work in Progress

Sometimes you need to switch branches but are not ready to commit half-finished work. git stash sets your uncommitted changes aside, leaving a clean working directory. You can reapply them later.

  • git stash saves and removes current changes.
  • git stash list shows saved stashes.
  • git stash pop reapplies the most recent stash and removes it from the list.

Stashes are stored on a stack, so you can keep several at once.

# Shelve current work, switch branch, then restore it
git stash
git switch hotfix
# ... later ...
git stash pop

16 Branching Strategies: GitFlow vs Trunk-Based

Teams adopt conventions for how branches are used:

  • GitFlow uses long-lived branches such as main, develop, plus feature/*, release/* and hotfix/* branches. It is structured but can be heavyweight.
  • Trunk-based development keeps a single main branch (“the trunk”). Developers integrate small changes frequently via short-lived branches, relying heavily on automated testing. It favours continuous delivery.

There is no single right answer — GitFlow suits scheduled releases, while trunk-based suits fast, continuous deployment.

# Trunk-based: short-lived branch, merged quickly
git switch -c quick-fix
# make a small change, then merge back to main
git switch main
git merge quick-fix

17 Pull/Merge Requests and Code Review

On platforms like GitHub and GitLab, you propose changes through a pull request (GitHub) or merge request (GitLab). It bundles a branch’s commits and asks maintainers to review and merge them into the main branch.

Code review is the practice of having teammates examine the proposed changes before they merge. Benefits include catching bugs early, sharing knowledge, and keeping a consistent style. Reviewers can comment, request changes, or approve. Automated checks (CI tests) usually run on the request too.

# Push your feature branch so a pull request can be opened
git switch -c feature/search
git push -u origin feature/search
# then open the pull request on the hosting platform

18 Writing Good Commit Messages

A clear commit message explains why a change was made, not just what. A widely used convention has a short subject line (about 50 characters, imperative mood like “Add” or “Fix”), a blank line, then an optional body giving context.

  • Imperative mood: “Fix login bug”, not “Fixed” or “Fixes”.
  • Keep the subject concise; wrap the body at ~72 columns.
  • Explain reasoning and trade-offs in the body when needed.

Good messages make history searchable and help future readers (including you) understand decisions.

# Subject + body via repeated -m flags
git commit -m "Fix off-by-one in pagination" -m "Last page dropped one item because the count was inclusive."

🎓 Certificate of Completion

🔒 Complete every lesson quiz above with 90%+ to unlock your downloadable certificate.