Git & GitHub Handbook Course home
git-handbook/from-zero-to-advancedPublic

Git & GitHub: From Zero to Advanced

A plain-English handbook that takes you from your first commit to team workflows. Every idea comes with a diagram, a worked example and a practice task.

parts6levelbeginner to advancedlanguageEnglishchapters44
handbookComplete handbook, all six parts44 chapters
Part 1: FoundationWhat Git is, where it came from, and how to set it up5 chapters
What is version control?Why every project needs a time machine6 min
A short history of GitBitKeeper, Linus Torvalds and 20055 min
Git vs GitHub vs GitLabThe engine and the garage4 min
Installing GitOptional for the course. Codespaces already has Git4 min
First-time configurationYour name, email and defaults6 min
Part 2: Git BasicsTrack, save, inspect and undo changes in a local project8 chapters
Your first repositoryinit, the .git folder and status4 min
The three areas of GitWorking directory, staging area, repository4 min
Making commitscommit, messages, amend and good habits4 min
Viewing historylog, show, diff and blame3 min
Ignoring files.gitignore patterns and what to ignore3 min
Undoing changesrestore, reset, revert and clean4 min
Renaming and deleting filesgit mv, git rm and restoring deleted files3 min
How Git stores dataObjects, hashes and HEAD3 min
Part 3: Branching and MergingWork in parallel and combine work safely7 chapters
Branches and HEADbranch, switch and detached HEAD5 min
MergingFast-forward and three-way merges5 min
Merge conflictsReading markers and resolving conflicts step by step3 min
RebaseRebasing, merge vs rebase and the golden rule3 min
Cherry-pickCopying individual commits3 min
StashSaving and restoring work in progress3 min
TagsLightweight and annotated tags, versions and releases3 min
Part 4: GitHub and CollaborationShare code, review it and contribute to other projects10 chapters
Remotes and cloningCreating a GitHub repository, origin and clone3 min
Push, pull and fetchSharing and receiving work safely4 min
Authentication: SSH keys and tokensSetting up secure access4 min
ForksForking, syncing and upstream3 min
Pull requestsOpening, reviewing and merging3 min
Code reviewGiving and receiving feedback on GitHub3 min
Issues, labels and projectsTracking work on GitHub3 min
GitHub PagesPublishing a static site from a repository3 min
Repository hygieneREADME, licence, CONTRIBUTING and templates3 min
Contributing to open sourceFinding a project and sending your first pull request3 min
Part 5: AdvancedAutomate checks, recover lost work and secure a repository8 chapters
GitHub ActionsYour first workflow3 min
Actions in practiceTest on several versions, store secrets and deploy3 min
Branch protection and CODEOWNERSRulesets and required reviews3 min
Git hooksPre-commit checks and shared hook tools3 min
Reflog and recoveryUndoing the undo3 min
Bisect and interactive rebaseHunting bugs and tidying history3 min
Submodules, monorepos and large filesSubmodules, monorepos and Git LFS3 min
Security: secrets, Dependabot and signed commitsProtecting your code and accounts4 min
Part 6: Practice and ReferenceTeam workflows, common mistakes, cheat sheet and glossary6 chapters
Branching strategiesGitHub Flow, Git Flow and trunk-based development4 min
Team best practicesCommits, pull requests, reviews and onboarding3 min
Common mistakes and fixesA troubleshooting guide with commands3 min
Cheat sheetQuick reference3 min
Interview questionsPractise your answers5 min
GlossaryKey words from A to Z3 min

How to read this handbook

You need no prior knowledge. If you can open a terminal and type a command, you can follow along.

Read the parts in order the first time, because each one builds on the last. Every chapter follows the same seven steps, so you always know where to look.

  1. ConceptThe idea in two or three sentences
  2. AnalogyA real-life comparison
  3. DiagramWhat happens inside the repo
  4. CommandsEach command with sample output
  5. MistakesWhat goes wrong and the fix
  6. RecapA one-minute revision list
  7. ExerciseA task to try yourself

Conventions

In a dark code block, a line that starts with $ is a command you type. The $ itself is not part of the command. Lines without it are the output Git prints back. The copy button copies only the commands.

$ git status
On branch main
nothing to commit, working tree clean

Words in <angle brackets> are placeholders. In git checkout <branch-name> you type the real branch name and leave out the brackets. Tick the boxes in each exercise to track progress; the sidebar shows a check beside a finished chapter.

If you are taking the Git Learning Portal

This handbook is the textbook. The stage guide is the worksheet: what to click, what to paste, and what to do when a check fails.

  1. Readthe chapters listed on the stage page
  2. Startan issue, choose the stage, wait for the bot comment
  3. Workin GitHub Codespaces in the browser. You do not install Git for stage 1
  4. Submita second issue. If a box is empty, follow the fail link in the reply
Important

Create git-lab from the template in the browser. Do not run git init or mkdir on your computer for the course. Chapter 6 still teaches git init so you know what a repository is. If a screen looks wrong, open Screens you will see.

Open stage 1 Stage 1 guide

Tip

To get a PDF copy, use the Save as PDF button. If your browser blocks it inside a preview, open this page in its own tab, press Ctrl+P (Cmd+P on a Mac) and choose Save as PDF. The print layout is set up for A4.

1

Foundation

Why version control exists, where Git came from, how Git and GitHub relate, and a working Git setup on your machine.

Part 1Chapter 16 min read

What is version control?

Version control records every change made to a set of files, so you can go back to any earlier state, see who changed what, and work with other people without overwriting their work.

1.1 The problem it solves

Everyone has seen a folder like this:

report.docx
report_final.docx
report_final_v2.docx
report_final_v2_REALLY_FINAL.docx
report_final_v2_REALLY_FINAL_ravi_edits.docx

Nobody knows which file is the latest, what changed between them, or who changed it. Now imagine 500 source files and 10 developers. Three things go wrong:

  • Lost work. Someone overwrites a file and the earlier version is gone for good.
  • No history. A bug appears and nobody can tell which change caused it.
  • Collision. Two people edit the same file and one person's changes silently disappear.

A version control system (VCS) fixes all three. It keeps every version, labels each change with its author, date and reason, and helps merge work from many people.

1.2 Analogy: a time machine for your project

Think of a video game with save points. Before a hard level you save. If you fail, you reload and try again. Each commit in Git is a save point with a name and a note, and you can return to any save point whenever you like.

commit 1 commit 2 commit 3 commit 4 Add login page Fix typo Add tests Update docs HEAD go back to any save point
Each commit is a save point. HEAD marks the one you are standing on.

It is also like Google Docs version history, with more control: you decide when a save point is made, you write a note for it, and it works for any type of file.

1.3 Three generations of version control

GenerationHow it worksExamplesMain weakness
LocalThe version database lives on one computerRCSNo collaboration; a disk failure loses everything
CentralizedOne server holds the history; developers check files out of itCVS, SubversionIf the server is down nobody can save history; it is a single point of failure
DistributedEvery developer has a full copy of the whole historyGit, MercurialA few more concepts to learn at the start
Centralized Central server Dev A Dev B Dev C One copy of the history Distributed (Git) Remote (GitHub) full history Dev A full history Dev B full history Every copy has the full history
If the central server dies, the project is at risk. In Git, any developer's copy can restore it.

When you clone a Git repository you get the complete history, not just the latest files. That is why most Git commands work without internet.

1.4 Key terms you will see everywhere

TermPlain meaning
Repository (repo)A project folder together with its full recorded history
CommitOne saved snapshot of your project, with a message and an author
BranchA separate line of work that does not disturb the main line
MergeCombining the work of two branches into one
RemoteA copy of the repository on another machine or server, such as GitHub
CloneDownloading a full copy of a remote repository
Note

Do not memorise these now. Each term gets its own chapter with examples.

1.5 Why teams cannot work without it

  • Collaboration: ten people can work on one codebase at the same time.
  • Traceability: every line can be traced to a person, a date and a reason.
  • Safety: a mistake is never permanent, because you can return to an earlier commit.
  • Experimentation: try a risky idea on a branch and throw it away if it fails.
  • Release management: mark exactly which version went to production.

1.6 Common mistakes

Warning

Copying folders as backups. A folder copy has no notes, no author and no way to merge. Use commits instead.

  • Thinking version control is only for code. It works for documents, configuration and notebooks too. Very large binary files need extra tools (Git LFS, in Part 5).
  • Waiting too long to start. Track the project from day one, not after a problem appears.
Quick recap
  • Version control records every change to your files.
  • Local, centralized and distributed are the three generations.
  • Git is distributed: every clone holds the full history.
  • A commit is a save point; a repository is the project plus its history.
Practice exercise
  • Think of a project from the past year and write down three moments when you wished you could go back.
  • For each moment, note what information (who, when, why) would have helped most.
  • Keep the list. Git records exactly that information, as Part 2 shows.
Part 1Chapter 25 min read

A short history of Git

Git was created in April 2005 by Linus Torvalds, the creator of Linux, because the Linux kernel project suddenly lost the version control tool it depended on.

2.1 Before Git: the BitKeeper story

The Linux kernel is one of the largest collaborative software projects in the world. Until 2002 its changes were passed around as patches and archives, which did not scale. From 2002 the kernel team used a proprietary distributed tool called BitKeeper, offered to the project free of charge.

In April 2005 the relationship broke down. The company behind BitKeeper withdrew the free licence after a dispute about reverse-engineering its protocol. The kernel developers now had thousands of contributors and no tool.

2.2 A tool built in days

Torvalds found no existing tool that met his goals, so he wrote a new one. His requirements:

  • Speed: applying a patch should take seconds, even for a huge project.
  • Simple design: a small, understandable core.
  • Parallel work: thousands of branches that merge easily.
  • Fully distributed: no single central server required.
  • Integrity: impossible to change history without anyone noticing.

A first version worked within days, and the kernel began using Git for its own development within about two weeks. The name "git" is British slang for an unpleasant person; Torvalds has joked that he names his projects after himself. Junio Hamano has maintained Git since July 2005, and Git 1.0 was released in December 2005.

2.3 Timeline of milestones

1982 RCS: early local version control 1990 CVS: first widely used centralized tool (approximate) 2000 Subversion and BitKeeper appear Apr 2005 Linus Torvalds creates Git Dec 2005 Git 1.0 is released; Junio Hamano maintains it 2008 GitHub is founded 2011 GitLab is started 2018 Microsoft acquires GitHub 2020 New GitHub repositories default to the branch name main
Grey: earlier tools. Orange: Git. Purple: hosting platforms. Green: the move from master to main. Early years are approximate.

2.4 Why Git won

  • It is fast, because most operations happen on your own machine.
  • Branching is cheap, so teams create branches freely.
  • It stores snapshots and checks content with hashes, so history is trustworthy.
  • It is free and open source.
  • Websites like GitHub made sharing and reviewing code easy for everyone.

2.5 Common mistakes

  • Confusing Git with GitHub. They are different things; Chapter 3 explains how.
  • Assuming Git is only for Linux. It runs on Windows, macOS and Linux.
Quick recap
  • Git was created in 2005 by Linus Torvalds after BitKeeper's free licence ended.
  • Its goals: speed, simple design, parallel work, distribution and integrity.
  • Junio Hamano has maintained Git since 2005.
  • GitHub arrived in 2008 and made Git popular far beyond the Linux community.
Practice exercise
  • Open a terminal and run git --version.
  • Write down what you see. "command not found" is fine; you install Git in Chapter 4.
Part 1Chapter 34 min read

Git vs GitHub vs GitLab vs Bitbucket

Git is the tool that tracks your changes on your computer. GitHub, GitLab and Bitbucket are websites that host Git repositories online so teams can share and review them.

3.1 Analogy: the engine and the garage

Git is a car engine: it does the real work and runs on your own machine. GitHub is a big garage and showroom. It stores your car (the repository), lets other people see it, lets mechanics suggest improvements, and offers extra services such as testing. You can run the engine without the garage, but the garage is useless without the engine. Likewise, email is a technology and Gmail is a service built on it.

Your computer Git, local repository Hosting service GitHub, GitLab, Bitbucket push pull, clone
Git works on the left with no internet. The hosting service on the right is where you share.

3.2 What Git does and what GitHub adds

QuestionGitGitHub
What is it?A free, open-source command-line toolA website and cloud service owned by Microsoft
Where does it run?On your own computerOn the internet
Needs internet?Not for most commandsYes
Main jobTrack changes, branch, mergeHost repositories, enable collaboration and review
ExtrasNone beyond version controlPull requests, issues, project boards, Actions, Pages, security alerts
Use one without the other?Yes, Git works aloneNo, it is built on Git

3.3 The main hosting platforms

All three use Git underneath, so the commands you learn work on each of them. This handbook uses GitHub for online examples because it is the most widely used and has a generous free plan.

PlatformKnown forTypical users
GitHubLargest community, open source, GitHub Actions, PagesIndividuals, open-source projects, companies of all sizes
GitLabBuilt-in CI/CD and DevOps tools; can be self-hostedTeams that want one integrated DevOps platform
BitbucketTight integration with Jira and other Atlassian toolsTeams already using Atlassian products

3.4 Common mistakes

  • Saying "I pushed to Git". You push to a remote such as GitHub. Git is the tool, GitHub is the place.
  • Treating GitHub as a guaranteed backup. It is hosting. Keep important repositories cloned in more than one place.
Caution

Check the visibility setting every time you create a repository. A private project made public by accident is hard to take back.

Quick recap
  • Git is a local version control tool; GitHub is an online service built around it.
  • GitLab and Bitbucket are alternatives and also use Git.
  • Git commands are the same on every platform.
Practice exercise
  • Create a free account at github.com with a professional username. It appears in your profile address and every contribution.
  • Add a profile photo and a one-line bio.
Part 1Chapter 44 min read

Installing Git

Installing Git takes about five minutes on any operating system, and you can confirm it worked by running git --version.

Course

If you are taking the Git Learning Portal, skip this chapter for stage 1. Work in GitHub Codespaces from the Start comment. Git is already there and signed in. Come back here only if you want Git on your own computer. Stage 1 guide ยท Open stage 1

4.1 Pick your operating system

Tip

The tabs below try to open on your own operating system. Choose another tab if you set up a different machine.

  1. Download the installer from the official website, git-scm.com.
  2. Run it. The defaults are fine for beginners, but check these screens:
    • Default editor: choose Visual Studio Code if you have it.
    • Initial branch name: choose "Override the default branch name" and enter main.
    • PATH environment: keep "Git from the command line and also from 3rd-party software".
  3. Finish, then open Git Bash from the Start menu. Git CMD is the same Git program in a different window, not a second course.

Or use one command in PowerShell:

$ winget install --id Git.Git -e --source winget

Let macOS install the command line tools. If Git is missing, a window offers to install it.

$ git --version

With Homebrew you can install a newer version:

$ brew install git

Use your distribution's package manager.

# Debian, Ubuntu
$ sudo apt update
$ sudo apt install git

# Fedora
$ sudo dnf install git

# Arch
$ sudo pacman -S git

4.2 Verify the installation

Open a new terminal window and run:

$ git --version
git version 2.45.0

Your version number will probably differ, and that is fine. Any reasonably recent version works with this handbook.

4.3 Common mistakes

  • Terminal opened before installing. It does not see new programs until you close it and open a new one.
  • "git is not recognized" on Windows. The PATH option was skipped. Run the installer again and choose the recommended PATH option.
  • Opening Git CMD because the Start issue appeared. The issue page is waiting for a bot comment. Use Codespaces from that comment. You do not need Git CMD for the course.
Important

Download Git only from git-scm.com or your system's package manager, never from an unofficial site.

Quick recap
  • Windows: installer from git-scm.com, or winget.
  • macOS: git --version triggers installation, or use Homebrew.
  • Linux: install the git package.
  • Always confirm with git --version.
Practice exercise
  • If you use Codespaces, open a terminal there and run git --version. If you use your own computer, install Git first, then run it.
  • Run git help and read the list of common commands. You meet most of them in Part 2.
Part 1Chapter 56 min read

First-time configuration

Before your first commit you must tell Git who you are, because every commit records its author's name and email.

Course

Codespaces already uses your GitHub name and email. Skip the commands in this chapter until you install Git on your own computer. If a check says your commits are not counted, the email on the commit is not verified on GitHub. Fix: commits are not counted

5.1 The three configuration levels

Git reads settings from three places. A more specific level overrides a more general one.

LevelFlagApplies toTypical use
System--systemEvery user on the computerRarely changed
Global--globalAll repositories of your user accountYour name, email and editor
Local--local (default)One repository onlyA different email for one project

5.2 Build your setup commands

Fill in your details and the commands below update as you type. Nothing is sent anywhere; this runs in your browser. Copy the result into your terminal.

Setup command builder
Important

Use the same email address that you registered on GitHub. If the emails differ, GitHub does not link your commits to your profile and they do not appear in your contribution graph.

  • Default branch. Older Git versions named the first branch master. GitHub and most teams now use main; the command above makes every new repository start on it.
  • Line endings. Windows ends lines with two hidden characters, macOS and Linux use one. The core.autocrlf setting stops this from creating noisy differences in mixed teams.

5.3 Check your settings

$ git config --list
user.name=Your Name
user.email=you@example.com
init.defaultbranch=main
core.editor=code --wait

# read a single value
$ git config user.name
Your Name

Settings live in a plain text file called .gitconfig in your home folder. You can open it in an editor and change values by hand.

5.4 Time-saving aliases

An alias is a short name for a longer command. Add these later, once you are comfortable.

$ git config --global alias.st status
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.lg "log --oneline --graph --all"

After this, git st does the same as git status.

5.5 Common mistakes

  • Skipping the identity step. Git may refuse to commit, or guess a wrong name and email from your computer.
  • Forgetting quotes around a name with a space, such as "Your Name".
Warning

Commit emails are public in a public repository. If you do not want your real address exposed, use the private no-reply address from your GitHub email settings.

Quick recap
  • user.name and user.email are mandatory; set them once with --global.
  • Set init.defaultBranch main so new repositories start on main.
  • Configure an editor and line endings for your operating system.
  • git config --list shows everything Git currently knows about you.
Practice exercise
  • Set your name and email, matching your GitHub account.
  • Set the default branch to main and choose your editor.
  • Run git config --list and check every value.
  • Create the git lg alias. You will use it in Part 2 to view history.
Part 1 complete

Next up is Part 2: Git Basics, where you create your first repository and make your first commits.

2

Git Basics

Track, save, inspect and undo changes in a local project.

Part 2Chapter 64 min read

Your first repository

Creating a repository turns an ordinary folder into a project that Git can track.

Course

For the Git Learning Portal, do not run git init or mkdir on your computer. Create git-lab from the template in the browser, then open it in Codespaces. This chapter still uses git init so you can see what a repository is. Stage 1 guide ยท I already have GitHub. Do I still make a folder?

6.1 Creating a repository with git init

A repository is a folder that Git is watching. Any folder can become one with a single command.

$ mkdir hello-git
$ cd hello-git
$ git init
Initialized empty Git repository in /home/you/hello-git/.git/

That is all. Git created a hidden folder called .git inside your project. Everything Git knows about your project lives in that folder: the history, the settings and the branches. Your own files stay where they are.

Warning

Never delete the .git folder by accident. If you delete it, the project becomes an ordinary folder again and its entire history is gone.

6.2 What is inside the .git folder

You do not need to edit these files, but it helps to know what they are.

ItemWhat it holds
HEADA pointer to the branch or commit you are currently on
configSettings for this repository only (the local level from Chapter 5)
objects/Every file version and commit Git has saved, stored by hash
refs/Pointers to branch tips and tags
indexThe staging area (explained in the next chapter)
$ ls -a
.  ..  .git
$ ls .git
HEAD  config  description  hooks  info  objects  refs

6.3 Checking the state with git status

git status is the command you will type most often. It tells you which branch you are on and what has changed.

$ git status
On branch main

No commits yet

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

Now create a file and ask again.

$ 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)

Untracked means Git can see the file but is not recording it yet. You will fix that in the next chapter.

1 Untracked Git sees the file but does not record it 2 Staged You marked it for the next commit with git add 3 Committed Saved permanently in the history 4 Modified You changed it again after the last commit
The life of a file in Git

6.4 Cloning an existing repository

Often you start from a project that already exists online. git clone downloads the whole repository, history included.

$ git clone https://github.com/git/git-scm.com.git
Cloning into 'git-scm.com'...
$ cd git-scm.com

Clone creates a new folder named after the repository. Cloning from GitHub is covered fully in Part 4.

6.5 Common mistakes

  • Running git init inside another repository. You then have a repository inside a repository, which confuses Git. Check with git status first; if it says "not a git repository" you are safe to initialise.
  • Initialising your home folder. Always create a project folder first. Running git init in ~ makes Git try to track everything you own.
  • Running Git commands outside a repository. The error fatal: not a git repository simply means you are in the wrong folder.
  • Making a folder on your computer for the course. A folder is not a GitHub repository. For stage 1, use the template link in the Start comment, then Codespaces.
  • Opening the yellow Compare & pull request banners on git-lab. greeting-a and greeting-b come with the template. Ignore them in every stage, and do not merge them. Stage 3 makes its own greeting branches in Codespaces. Yellow banners
Tip

Your terminal prompt can show the current branch. Git Bash does this by default, and tools such as Oh My Zsh add it on macOS and Linux.

Quick recap
  • git init turns a folder into a repository by creating a hidden .git folder.
  • .git holds all history and settings; never delete it.
  • git status shows your branch and which files are untracked, modified or staged.
  • git clone copies an existing repository with its full history.
Check yourself

1. Which command turns an ordinary folder into a Git repository?

2. A file Git can see but is not recording is called...

Practice exercise
  • Create a folder named hello-git and run git init inside it.
  • Run ls -a (or dir /a on Windows) and find the .git folder.
  • Create README.md, then run git status and read the output.
Part 2Chapter 74 min read

The three areas of Git

Git moves your work through three areas, and understanding them explains almost every Git command.

Course

The stage 1 command block does this three times: edit a file (working directory), git add (staging area), git commit (repository). Paste the whole block so you get three commits. Stage 1 guide

7.1 The idea: a photo studio

Imagine a photo studio. The working directory is the stage where you arrange people and props. The staging area is the shelf where you place exactly the items you want in the next photo. The repository is the album where finished photos are stored forever. You can rearrange the stage as much as you like. Only what you place on the shelf gets photographed, and once a photo is in the album it stays there.

Working directory The files you edit Staging area What the next commit will contain Repository Permanent history in .git git add git commit git restore, git switch git restore --staged
The three areas and the commands that move work between them

7.2 Why a staging area exists

Many beginners ask why Git does not just save everything you changed. The staging area lets you build clean commits. If you fixed a bug and also reformatted another file, you can stage and commit them separately. Each commit then tells one story, which makes history easy to read and easy to undo.

7.3 Adding files with git add

$ 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 file is now staged. Useful variations:

CommandWhat it stages
git add file.txtOne file
git add file1.txt file2.txtSeveral named files
git add src/Everything inside a folder
git add *.pyAll Python files in the current folder
git add .Everything new or changed from here downward
git add -AEverything new, changed or deleted in the whole project
git add -pPick individual pieces of a file, one at a time

7.4 A file can be in two states at once

Edit a file after staging it and Git remembers both versions: the one you staged, and the newer one in your working directory.

$ echo "More text" >> README.md
$ git status
Changes to be committed:
	new file:   README.md

Changes not staged for commit:
	modified:   README.md

Only the staged version goes into the next commit. Run git add README.md again to include the newer edit.

7.5 Staging part of a file

git add -p shows each changed chunk (called a hunk) and asks what to do.

$ git add -p
@@ -1,2 +1,3 @@
 # Hello Git
+More text
Stage this hunk [y,n,q,a,d,s,e,?]? y
KeyMeaning
yStage this hunk
nDo not stage this hunk
sSplit into smaller hunks
qQuit

7.6 Common mistakes

  • Using git add . blindly. It can stage secrets, build files or large data. Always run git status before committing.
  • Forgetting to stage again after editing. The commit contains the staged version, not your latest edit.
  • Thinking git add saves your work. Staging is only a preparation step. Nothing is saved to history until you commit.
Quick recap
  • Working directory, staging area and repository are the three areas.
  • git add moves changes into the staging area; git commit moves them into the repository.
  • The staging area lets you build small, focused commits.
  • git add -p stages part of a file.
Check yourself

1. What does git add do?

2. You edit a file after staging it. Which version goes into the next commit?

Practice exercise
  • Create two files, a.txt and b.txt, and stage only a.txt. Check with git status.
  • Edit a.txt after staging it and run git status to see the file listed twice.
  • Practise git add -p on a file with two separate edits.
Part 2Chapter 84 min read

Making commits

A commit is a permanent snapshot of your staged changes together with a message explaining why you made them.

Course

Stage 1 needs three commits after your Start issue: the code file, the README line, and the *.log ignore rule. Your name goes in data/profile.json and is committed with the README. It does not replace those three commits. If Submit says you only have two commits, paste the rest of the Start block. Fix: only two commits ยท Fix: challenge code file

8.1 Your first commit

$ git commit -m "Add README"
[main (root-commit) 3f2a9c1] Add README
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

Let us read this output. main is the branch, 3f2a9c1 is the start of the commit's unique ID (its hash), and the last lines say what changed.

8.2 What a commit contains

Snapshot Your files exactly as staged Author and date Who and when Message Why the change was made Parent The previous commit stored with explained by follows
Anatomy of a commit

Every commit points to its parent, the commit before it. These links form the history chain that you saw in Chapter 1.

Add README Add login Fix typo HEAD main
A growing history. HEAD is where you are now.

8.3 Commit command variations

CommandWhat it does
git commit -m "message"Commit with a one-line message
git commitOpen your editor to write a longer message
git commit -a -m "message"Stage all changes to tracked files, then commit
git commit --amendReplace the last commit with a new one
git commit --allow-empty -m "message"Create a commit with no file changes
Note

-a only picks up files Git already tracks. Brand new files still need git add.

8.4 Writing good commit messages

A good message explains why, not just what, and makes sense to a stranger a year from now.

Fix crash when the username is empty

The login form passed an empty string to validate(), which
raised an exception. Return a friendly error instead.
  • Write a short first line of about 50 characters, in the imperative mood: "Add", "Fix", "Remove".
  • Leave a blank line, then add details only if they help.
  • Describe one logical change per commit.
Weak messageBetter message
updateAdd password length check to signup
fixed stuffFix off-by-one error in pagination
final versionPrepare release 1.2.0

8.5 Fixing the last commit with --amend

You committed, then noticed a typo or a forgotten file. Amend rewrites the last commit.

$ git add forgotten.txt
$ git commit --amend -m "Add README and licence"
Caution

Never amend a commit that you have already pushed to a shared branch. Amending creates a different commit, and teammates who already have the old one will run into conflicts.

8.6 Common mistakes

  • Committing with no message or a vague one. Future you will not remember what "stuff" meant.
  • Huge commits that mix unrelated changes. Use git add -p to split them.
  • Committing secrets such as passwords or API keys. Removing them later is painful. Part 5 covers prevention.
  • Skipping the Start command block. The portal counts only commits after Start that are pushed to GitHub. Paste every line, then git push.
Quick recap
  • A commit is a snapshot plus author, date, message and a link to its parent.
  • git commit -m "message" saves what is staged.
  • Write short, imperative messages that explain why.
  • --amend fixes the last commit, but only before you share it.
Check yourself

1. Which part of your work does a commit save?

2. Which message follows good practice?

Practice exercise
  • Make your first commit with a clear message.
  • Change a file, stage it, commit it, then fix the message with git commit --amend.
  • Write one commit whose message explains why, not only what.
Part 2Chapter 93 min read

Viewing history

Git remembers everything, and a handful of commands let you read that memory in many different ways.

Course

The last line of the stage 1 block is git log --oneline. You should see at least three commits you just made. If you see only one or two, you skipped part of the block. Fix: only two commits

9.1 git log: the history list

$ git log
commit 9a1c4e7d2b8f0c3a5e6d7f8a9b0c1d2e3f4a5b6c (HEAD -> main)
Author: Your Name <you@example.com>
Date:   Mon Oct 5 10:12:03 2026 +0530

    Fix typo in README

commit 3f2a9c1e5b7d4a8c9d21f6e5a4b3c2d1e0f9a8b7
Author: Your Name <you@example.com>
Date:   Mon Oct 5 09:40:11 2026 +0530

    Add README

Newest commits come first. Press q to leave the scrolling view.

9.2 Making log readable

CommandResult
git log --onelineOne line per commit
git log --graph --oneline --allDraw branches as an ASCII graph
git log -3Only the last three commits
git log --author="Priya"Commits by one author
git log --since="2 weeks ago"Commits from a time range
git log --statShow which files changed in each commit
git log -- path/file.txtHistory of one file
git log --grep="login"Search commit messages
$ git log --oneline
9a1c4e7 Fix typo in README
3f2a9c1 Add README
Tip

The git lg alias from Chapter 5 gives you this compact graph view in three letters.

9.3 git show: look inside one commit

$ git show 3f2a9c1
commit 3f2a9c1e5b7d4a8c9d21f6e5a4b3c2d1e0f9a8b7
Author: Your Name <you@example.com>

    Add README

diff --git a/README.md b/README.md
new file mode 100644
+# Hello Git

You only need the first 7 or so characters of the hash, as long as they are unique.

9.4 git diff: compare changes

Diff shows what changed. Which two things it compares depends on the options.

Working directory Your edits Staging area Staged changes Last commit HEAD git diff git diff --staged git diff HEAD
What each git diff form compares
diff --git a/README.md b/README.md
@@ -1 +1,2 @@
 # Hello Git
+More text

Lines beginning with + were added, lines beginning with - were removed, and @@ marks the position in the file.

CommandCompares
git diffWorking directory against staging area
git diff --stagedStaging area against the last commit
git diff HEADWorking directory against the last commit
git diff 3f2a9c1 9a1c4e7Two specific commits
git diff main featureTwo branches

9.5 git blame: who changed this line

$ git blame README.md
3f2a9c1e (Your Name 2026-10-05 1) # Hello Git
9a1c4e7d (Priya Shah 2026-10-05 2) More text

Blame shows, for every line, the commit and author that last changed it. Use it to ask "why is this here?", not to assign fault.

9.6 Other handy commands

  • git shortlog -sn counts commits per author.
  • git show HEAD~2 shows the commit two steps before the latest.
  • git log -p shows the full patch for each commit.

9.7 Common mistakes

  • Being stuck in the pager. Press q to exit a long log.
  • Expecting git diff to show staged changes. Add --staged for those.
  • Pasting a full 40-character hash. The short form works.
Quick recap
  • git log lists history; --oneline and --graph make it readable.
  • git show displays one commit in full.
  • git diff compares areas, commits or branches.
  • git blame shows who last changed each line.
Check yourself

1. Which command shows changes you have already staged?

2. How do you leave the log view?

Practice exercise
  • Make three small commits, then run git log --oneline.
  • Edit a file and compare git diff with git diff --staged before and after git add.
  • Run git blame on a file and find the commit for one line.
Part 2Chapter 103 min read

Ignoring files

A .gitignore file tells Git which files to leave alone, such as secrets, build output and temporary files.

Course

Stage 1 needs a line that is exactly *.log in .gitignore, committed after Start. The Start block adds it. If Submit says the log rule is missing, you skipped those lines. Fix: gitignore is missing the log rule

10.1 Why some files must not be tracked

Some files should never enter your history:

  • Passwords, API keys and .env files.
  • Dependencies such as node_modules/ or venv/, which can be downloaded again.
  • Build output, logs and cache files.
  • Editor or operating system files such as .DS_Store or .vscode/.

Ignoring them keeps the repository small, clean and safe.

10.2 Creating a .gitignore

Create a plain text file named .gitignore in the project root. Each line is a pattern.

# Python
__pycache__/
*.pyc
venv/

# Secrets
.env

# Logs
*.log

# Operating system
.DS_Store
$ git add .gitignore
$ git commit -m "Add .gitignore"

Commit the .gitignore itself so everyone on the team shares the same rules.

10.3 Pattern rules

PatternMatches
*.logAny file ending in .log, in any folder
build/A folder named build
/todo.txtOnly todo.txt in the project root
docs/*.pdfPDF files directly inside docs
**/tempA folder named temp at any depth
!important.logException: do not ignore this file
# commentA comment line
Note

The order matters. A later ! rule can re-include something an earlier rule ignored, but only if the parent folder itself is not ignored.

10.4 When a file is already tracked

.gitignore only affects files Git is not yet tracking. If you committed .env before ignoring it, Git keeps tracking it. Tell Git to stop, but keep the file on disk:

$ git rm --cached .env
rm '.env'
$ git commit -m "Stop tracking .env"
Caution

The file is still in your old history. If it contained a real secret, treat the secret as leaked and change it. Chapter 38 explains this.

10.5 Checking why a file is ignored

$ git check-ignore -v debug.log
.gitignore:3:*.log	debug.log
$ git status --ignored

10.6 A global ignore file

Rules for your own computer, such as editor files, belong in a global file so you do not repeat them in every project.

$ git config --global core.excludesfile ~/.gitignore_global

10.7 Ready-made templates

GitHub maintains a collection of .gitignore templates for most languages and frameworks. Start from the one that matches your stack, then adjust it. GitHub also offers to add one when you create a new repository.

10.8 Common mistakes

  • Ignoring after committing. Remember git rm --cached.
  • Ignoring a folder, then expecting an exception inside it to work. Ignore files, or use folder/* style patterns.
  • Ignoring everything with *. This hides real work. Be specific.
Quick recap
  • .gitignore lists patterns of files Git should not track.
  • Commit it so your whole team shares it.
  • Already tracked files need git rm --cached first.
  • Secrets in old history stay leaked until you rotate them.
Check yourself

1. You committed a file, then added it to .gitignore. What happens?

2. Which pattern ignores every .log file?

Practice exercise
  • Create a .gitignore that ignores *.log and a folder named build/.
  • Create debug.log and check that git status does not list it.
  • Use git check-ignore -v debug.log to see which rule matched.
Part 2Chapter 114 min read

Undoing changes

Git offers a safe way back at every stage, and choosing the right undo command depends on where your mistake lives.

11.1 First, where is the mistake

Git has several undo commands because a mistake can live in three different places. Find the place first, then pick the command.

Where the mistake isWhat it looks likeCommand
Working directoryYou edited a file and want the old version backgit restore <file>
Staging areaYou staged a file by mistakegit restore --staged <file>
Last commit (not shared)Wrong message or a forgotten filegit commit --amend
Last commits (not shared)You want to redo recent commitsgit reset
Shared commitSomeone else already has the commitgit revert <commit>

11.2 Discard changes in the working directory

$ git restore README.md

The file returns to its last committed (or staged) state.

Caution

This cannot be undone. Your unsaved edits are gone, because Git never recorded them.

11.3 Unstage a file

$ git add secret.txt
$ git restore --staged secret.txt

The file leaves the staging area, but your edits stay in the working directory.

11.4 git reset: move the branch back

git reset moves the current branch to an earlier commit. The three modes decide how much of your work is also reset.

C1 C2 C3 (unreferenced) HEAD main
After git reset HEAD~1, main and HEAD point to C2. C3 still exists until Git cleans it up.
ModeBranch movesStaging areaWorking directory
--softYesKeptKept
--mixed (default)YesClearedKept
--hardYesClearedCleared
$ git reset --soft HEAD~1
$ git reset HEAD~1
$ git reset --hard HEAD~1
  • Use --soft to redo a commit: your changes stay staged, ready to commit again.
  • Use --mixed to unstage and rethink.
  • Use --hard only when you truly want to throw the work away.
Caution

git reset --hard destroys uncommitted work. Check git status first.

11.5 git revert: undo safely in shared history

Reset rewrites history, which is dangerous once others have your commits. Revert adds a new commit that cancels an old one, so history is never rewritten.

C1 C2 C3 Revert C2 HEAD
git revert creates a new commit that cancels C2
$ git revert 3f2a9c1
[main 7b1d2e4] Revert "Add login"
 1 file changed, 5 deletions(-)

Use revert for anything that has been pushed to a shared branch.

11.6 git clean: remove untracked files

$ git clean -n
Would remove debug.log
$ git clean -f
Removing debug.log

Always run -n (dry run) first. Add -d to include untracked folders.

11.7 Decision guide

  • Not committed yet: restore.
  • Committed but not pushed: reset or --amend.
  • Pushed and shared: revert.
Tip

If you reset too far, the commits are not gone yet. Chapter 35 shows how git reflog finds them again.

11.8 Common mistakes

  • Using reset --hard casually. Prefer --soft or --mixed.
  • Resetting a shared branch and force-pushing. This breaks everyone else's history. Use revert.
  • Confusing restore with revert. Restore changes files; revert creates a commit.
Quick recap
  • git restore discards working changes; git restore --staged unstages.
  • git reset moves the branch; --soft, --mixed and --hard decide how much is reset.
  • git revert safely cancels a commit by adding a new one.
  • Use revert for shared history, reset only for local history.
Check yourself

1. A commit has already been pushed to the shared main branch and is wrong. What is safest?

2. Which command unstages a file but keeps your edits?

Practice exercise
  • Edit a file, then discard the edit with git restore.
  • Stage a file, then unstage it with git restore --staged.
  • Make two commits, run git reset --soft HEAD~1, and see the changes staged again.
  • Make a commit and undo it with git revert. Look at git log --oneline.
Part 2Chapter 123 min read

Renaming and deleting files

Git tracks file moves and deletions too, and the right commands keep the history clean.

12.1 Deleting a tracked file

$ git rm old-notes.txt
rm 'old-notes.txt'
$ git status
Changes to be committed:
	deleted:    old-notes.txt
$ git commit -m "Remove old notes"

git rm deletes the file from disk and stages the deletion in one step. If you delete a file in your file explorer instead, Git notices it as an unstaged deletion. Stage it with git add -A or git rm <file>.

12.2 Stop tracking but keep the file

$ git rm --cached config.local

This removes the file from Git's tracking but leaves it on disk. Pair it with .gitignore (Chapter 10).

12.3 Renaming and moving

$ git mv draft.txt final.txt
$ git status
Changes to be committed:
	renamed:    draft.txt -> final.txt

git mv is the same as renaming the file yourself and then running git add on both names. Git does not store renames explicitly. It detects them by comparing contents, so a rename plus tiny edits is still recognised.

12.4 Restoring a deleted file

Deleted something by mistake? It is still in history.

$ git restore old-notes.txt
$ git restore --source=HEAD~2 old-notes.txt

The second form brings the file back from two commits ago.

12.5 Common mistakes

  • Deleting with the file explorer and forgetting to stage. The deletion is not committed until you stage it.
  • Renaming and changing a file in one commit. If too much changes, Git may not recognise the rename. Rename first, commit, then edit.
Quick recap
  • git rm deletes and stages the deletion.
  • git rm --cached stops tracking but keeps the file.
  • git mv renames or moves a file and stages the change.
  • Deleted files can be brought back from history with git restore.
Check yourself

1. Which command stops tracking a file but keeps it on disk?

Practice exercise
  • Rename a file with git mv and commit the change.
  • Delete a file with git rm, commit, then bring it back with git restore --source.
Part 2Chapter 133 min read

How Git stores data

Git is a database of snapshots identified by hashes, and seeing its structure makes the commands feel logical.

13.1 Snapshots, not differences

Older tools stored a list of changes for every file. Git instead stores a snapshot of the whole project at each commit. Unchanged files are not copied again; the new snapshot simply points to the version that already exists. This is why branching and switching are so fast.

13.2 The four object types

Git stores everything as objects inside .git/objects, each named by a hash.

ObjectStoresAnalogy
BlobThe contents of one fileA page of text
TreeA folder: a list of names pointing to blobs and other treesA table of contents
CommitA pointer to a tree, plus author, date, message and parentA dated photo with a caption
TagA named pointer, often to a commitA bookmark
Commit Message, author, parent Tree Folder listing Blobs File contents points to points to
How one commit points to your files

13.3 Hashes: the fingerprint of content

Every object is named by a hash of its contents. By default Git uses SHA-1, a 40-character hexadecimal code. Identical content always gives an identical hash, and any tiny change produces a completely different one.

$ echo "hello" | git hash-object --stdin
ce013625030ba8dba906f756967f9e9ca394464a

This is why Git history is trustworthy: a commit's hash depends on its content and its parent's hash, so changing an old commit changes every hash after it. Git also has experimental support for SHA-256 as a stronger option.

13.4 Looking inside

$ git cat-file -t 3f2a9c1
commit
$ git cat-file -p 3f2a9c1
tree 8c3a1b9d0e7f2a4b6c5d8e9f0a1b2c3d4e5f6a7b
author Your Name <you@example.com> 1759640000 +0530
committer Your Name <you@example.com> 1759640000 +0530

Add README
$ git cat-file -p 8c3a1b9
100644 blob 2f8d6a1b7c9e0a3b5d4c6e8f9a0b1c2d3e4f5a6b	README.md

-t shows the type and -p pretty-prints the content. The hashes above are examples; yours will differ.

13.5 Branches and HEAD are just pointers

A branch is a tiny file that holds one commit hash. HEAD is a file that says which branch you are on.

$ cat .git/HEAD
ref: refs/heads/main
$ cat .git/refs/heads/main
9a1c4e7d2b8f0c3a5e6d7f8a9b0c1d2e3f4a5b6c

Creating a branch means writing a 41-byte file, which explains why it is instant. Chapter 14 builds on this.

13.6 Common mistakes

  • Thinking commits store only the differences. They store full snapshots, efficiently shared.
  • Editing files inside .git. Use Git commands instead, so the data stays consistent.
Quick recap
  • Git stores snapshots as objects: blobs, trees, commits and tags.
  • Objects are named by a hash of their content.
  • A branch is a pointer to a commit; HEAD points to the current branch.
  • Hashes make history tamper-evident.
Check yourself

1. What is a branch, inside Git?

Practice exercise
  • Run git cat-file -p HEAD in one of your repositories and follow the tree hash.
  • Open .git/HEAD and .git/refs/heads/ in a file explorer and find your branch.
3

Branching and Merging

Work on several things in parallel and combine the results safely.

Part 3Chapter 145 min read

Branches and HEAD

A branch is a separate line of work, so you can try ideas without disturbing the stable version of your project.

14.1 The idea: parallel drafts

Writing a report, you might copy the document to try a risky rewrite. If it works you keep it, and if not you throw the copy away. A branch gives you that without copying any files. Your stable work stays on main, while the experiment lives on its own branch.

C1 C2 C5 C3 C4 main feature
Two lines of work that share a starting point

Because a branch is only a pointer to a commit (Chapter 13), creating one is instant and costs almost no space.

14.2 Creating and listing branches

$ git branch feature-login
$ git branch
  feature-login
* main

The * marks the branch you are on. Creating a branch does not move you onto it.

14.3 Switching branches

$ git switch feature-login
Switched to branch 'feature-login'
$ git switch -c feature-search
Switched to a new branch 'feature-search'

git switch -c <name> creates and switches in one step, which is the form you will use most.

Note

Older tutorials use git checkout <branch> and git checkout -b <branch>. They still work. switch was added in 2019 to give branch changes a clearer name.

When you switch, Git rewrites the files in your working directory to match that branch. Work you committed on another branch seems to vanish and returns when you switch back.

14.4 HEAD: where you are

HEAD points to the branch you are on, and that branch points to its latest commit. Each new commit moves the branch forward, and HEAD follows.

C1 C2 C3 main HEAD feature-login
HEAD is on feature-login, so the next commit extends that branch

14.5 Everyday branch commands

CommandWhat it does
git branchList local branches
git branch -aList local and remote branches
git branch -m old newRename a branch
git branch -d nameDelete a merged branch
git branch -D nameForce-delete a branch, even if unmerged
git switch -Jump back to the previous branch
git branch -vvShow each branch's latest commit and upstream

14.6 Detached HEAD

If you check out a commit hash or a tag, HEAD points straight at a commit, not a branch. Git calls this a detached HEAD.

$ git switch --detach 3f2a9c1
HEAD is now at 3f2a9c1 Add README

You can look around safely. But a commit made here belongs to no branch and can be lost. To keep the work, give it a branch:

$ git switch -c rescue-work

To leave without keeping anything, run git switch main.

14.7 Naming branches

  • Use short lowercase names with hyphens: fix-login-bug.
  • Group by purpose with a prefix: feature/search, bugfix/crash, docs/readme.
  • Avoid spaces and personal names.

14.8 Uncommitted changes when switching

If your edits do not touch files that differ between the branches, they travel with you. If they would be overwritten, Git refuses to switch and asks you to commit or stash first (Chapter 19).

14.9 Common mistakes

  • Committing on main by accident. Check git branch before you start.
  • Forgetting which branch you are on. Use git status or a prompt that shows it.
  • Deleting an unmerged branch with -D. You may lose the only copy of that work.
Quick recap
  • A branch is a movable pointer to a commit; creating one is instant.
  • git switch -c name creates and enters a branch.
  • HEAD points to your current branch; commits move it forward.
  • Detached HEAD means HEAD points at a commit; create a branch to keep work done there.
Check yourself

1. What does git switch -c login do?

2. You made commits in a detached HEAD state. How do you keep them?

Practice exercise
  • Create a branch named feature-hello and switch to it.
  • Make a commit, switch back to main, and confirm the file disappears. Switch again and it returns.
  • Run git log --oneline --graph --all to see both branches.
Part 3Chapter 155 min read

Merging

Merging brings the work of one branch into another, and Git chooses between two methods depending on how the history looks.

15.1 The basic command

Move to the branch that should receive the work, then merge the other one in.

$ git switch main
$ git merge feature-login

The rule to remember: you merge into the branch you are standing on.

15.2 Fast-forward merge

If main has not moved since you branched, Git simply slides the main pointer forward. No new commit is needed.

C1 C2 C3 C4 main feature-login
Before: feature-login is ahead of main
C1 C2 C3 C4 main HEAD
After a fast-forward merge: main simply moved to C4
$ git merge feature-login
Updating 3f2a9c1..b81e6d2
Fast-forward
 login.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

15.3 Three-way merge

If both branches have new commits, a simple slide is impossible. Git compares three snapshots: the common ancestor and the two branch tips. It then creates a merge commit with two parents.

C1 C2 C5 C3 C4 main feature
Before: main and the feature have both moved on
C1 C2 C5 C3 C4 M main HEAD
After: the merge commit M joins both lines
$ git merge feature-login
Merge made by the 'ort' strategy.
 login.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Git opens your editor with a default message such as "Merge branch 'feature-login'". Save and close to finish.

15.4 Controlling the style of merge

OptionEffect
--no-ffAlways create a merge commit, even when a fast-forward is possible
--ff-onlyRefuse to merge unless a fast-forward is possible
--squashCombine all branch changes into one staged change, then you commit it yourself
--abortCancel a merge that is in progress

Teams choose between them. --no-ff keeps a visible record of each feature. --squash keeps main tidy with one commit per feature. GitHub offers the same three choices on pull requests (Chapter 25).

15.5 After merging: clean up

$ git branch -d feature-login
Deleted branch feature-login (was b81e6d2).

The commits are safe, because they are now part of main. Only the label is removed.

15.6 Common mistakes

  • Merging in the wrong direction. Check which branch you are on with git status.
  • Merging with uncommitted changes. Commit or stash first.
  • Never deleting old branches. They clutter the list. Delete them once merged.
Quick recap
  • You merge a branch into the one you are on: git merge <branch>.
  • Fast-forward just moves the pointer; a three-way merge makes a merge commit.
  • --no-ff, --ff-only and --squash change how the history looks.
  • Delete merged branches with git branch -d.
Check yourself

1. When can Git do a fast-forward merge?

2. A merge commit has how many parents?

Practice exercise
  • Create a branch, add a commit, and fast-forward merge it into main.
  • Make a commit on main and another on a branch, then merge to create a merge commit.
  • Draw the history with git log --graph --oneline.
Part 3Chapter 163 min read

Merge conflicts

A conflict happens when two branches change the same lines, and Git asks you to decide what the result should be.

16.1 Why conflicts happen

Git merges automatically when branches change different parts of a file. When both branches edit the same lines, Git cannot know which version you want. It stops and asks you. That is not an error, only a question that needs a human answer.

16.2 What a conflict looks like

$ git merge feature-login
Auto-merging app.py
CONFLICT (content): Merge conflict in app.py
Automatic merge failed; fix conflicts and then commit the result.

Open the file. Git has marked the conflicting area.

<<<<<<< HEAD
greeting = "Hello, user!"
=======
greeting = "Welcome back!"
>>>>>>> feature-login
MarkerMeaning
<<<<<<< HEADStart of your version (the branch you are on)
=======Divider between the two versions
>>>>>>> feature-loginEnd of the incoming version

16.3 Resolving it step by step

1 Run git status Find the files listed under "both modified" 2 Open each file Locate the conflict markers 3 Decide the result Keep one side, the other, or combine both 4 Delete the markers Remove every <<<<<<<, ======= and >>>>>>> line 5 git add the file This tells Git the conflict is resolved 6 Finish the merge Run git commit, or git merge --continue
The conflict resolution routine

Suppose you decide to combine both greetings. Edit the file to the final text you want and remove the markers.

greeting = "Welcome back, user!"
$ git add app.py
$ git commit
[main 4d5e6f7] Merge branch 'feature-login'

16.4 Useful commands during a conflict

CommandUse
git statusSee which files still conflict
git diffSee remaining conflicts
git merge --abortCancel and return to the state before the merge
git checkout --ours fileKeep your side of one file entirely
git checkout --theirs fileKeep the incoming side of one file entirely
git mergetoolOpen a visual merge tool
Tip

Visual Studio Code shows buttons above each conflict: Accept Current, Accept Incoming, Accept Both. Many people find this easier than editing markers by hand.

16.5 Making conflicts less likely

  • Pull the latest main into your branch often.
  • Keep branches short-lived and focused.
  • Talk to teammates before large refactors or file moves.
  • Keep functions and files small so edits rarely overlap.

16.6 Seeing more context

By default Git shows only two sides. The zdiff3 style also shows the common ancestor, which often makes the right choice obvious.

$ git config --global merge.conflictStyle zdiff3

16.7 Common mistakes

  • Leaving markers in the file. Search for <<<<<<< before you commit. A project with markers will not run.
  • Accepting one side without reading. You may silently throw away a teammate's work.
  • Panicking. git merge --abort always takes you back to safety.
Quick recap
  • Conflicts occur when both branches change the same lines.
  • Markers show your version, a divider and the incoming version.
  • Edit, remove markers, git add, then commit.
  • git merge --abort cancels the merge.
Check yourself

1. What must you do after fixing a conflicted file?

2. Which command cancels a merge in progress?

Practice exercise
  • Create a conflict on purpose: edit the same line differently on two branches and merge.
  • Resolve it by combining both versions and finish the merge.
  • Repeat, then cancel the second attempt with git merge --abort.
Part 3Chapter 173 min read

Rebase

Rebase replays your commits on top of another branch, which gives a straight, easy-to-read history.

17.1 The idea

Merging joins two histories with a merge commit. Rebasing takes your branch's commits and re-applies them one by one on top of the latest main, as if you had started your work from there.

C1 C2 C5 C3 C4 main feature
Before: feature branched from C2, but main has moved on to C5
$ git switch feature
$ git rebase main
Successfully rebased and updated refs/heads/feature.
C1 C2 C5 C3' C4' main feature
After: the feature commits are replayed on top of C5 (as new commits C3' and C4')

The history is now a straight line. The feature commits have the same changes but new hashes, because their parent changed.

17.2 Merge or rebase

MergeRebase
HistoryKeeps the true branching shapeGives a straight line
Extra commitsAdds a merge commitAdds none
Rewrites commitsNoYes (new hashes)
Safe on shared branchesYesNo
Typical useJoining finished workUpdating your own branch before a pull request

17.3 Rebase conflicts

Conflicts can appear while commits are replayed. Resolve them as in Chapter 16, then continue.

$ git add app.py
$ git rebase --continue
$ git rebase --abort
$ git rebase --skip
  • --continue carries on after you fixed the files.
  • --abort returns to how things were before the rebase.
  • --skip drops the commit that is causing trouble.

17.4 The golden rule of rebase

Caution

Never rebase commits that other people already have. Rebase creates new commits with new hashes. If teammates built on the old ones, their history and yours no longer match, and fixing it is painful.

Rebase your own local or personal-branch commits freely. Do not rebase main or any shared branch.

17.5 Pull with rebase

A normal git pull can add merge commits. This keeps your local history linear instead:

$ git pull --rebase
$ git config --global pull.rebase true

17.6 Common mistakes

  • Rebasing a shared branch. Follow the golden rule.
  • Force-pushing after a rebase without care. Use git push --force-with-lease, which refuses to overwrite work you have not seen.
  • Rebasing in a panic during conflicts. Abort and look at the state first.
Quick recap
  • Rebase replays your commits on top of another branch.
  • It creates new commits and a straight history.
  • Never rebase commits that are already shared.
  • Use --continue, --abort or --skip during conflicts.
Check yourself

1. Why must you not rebase commits others already have?

Practice exercise
  • Create a branch, then add a commit on main. Rebase the branch onto main.
  • Compare git log --oneline --graph before and after.
Part 3Chapter 183 min read

Cherry-pick

Cherry-pick copies a single commit from one branch onto another without merging everything else.

18.1 When you need it

Imagine a bug fix was committed on a feature branch, and the same fix is needed urgently on main, but the rest of the feature is not ready. Cherry-pick takes just that one commit.

C1 C2 F2' F1 F2 main feature
Cherry-picking commit F2 onto main creates a copy, F2'

18.2 The command

$ git switch main
$ git cherry-pick 8e4c1b7
[main a3b9d21] Fix null pointer crash
 1 file changed, 2 insertions(+)

The copy has a new hash, because it has a new parent.

CommandResult
git cherry-pick <hash>Copy one commit
git cherry-pick A B CCopy several commits
git cherry-pick A..BCopy the range after A up to B
git cherry-pick -x <hash>Add a note saying where it came from
git cherry-pick -n <hash>Apply the change but do not commit

18.3 Conflicts

If the change does not apply cleanly, Git stops. Resolve the files, then run:

$ git add file.py
$ git cherry-pick --continue
$ git cherry-pick --abort

18.4 When to use it, and when not to

  • Good for hotfixes that must reach a release branch quickly.
  • Good for rescuing one useful commit from an abandoned branch.
  • Poor as a routine way to move work. Duplicate commits make history confusing, and you may see the same change twice when the branches are merged later.

18.5 Common mistakes

  • Cherry-picking too much. If you need many commits, merge or rebase instead.
  • Forgetting the original still exists. The source branch keeps its own copy.
Quick recap
  • Cherry-pick copies selected commits to the current branch.
  • The copies get new hashes.
  • Use -x to record the source commit.
  • Resolve conflicts, then --continue.
Check yourself

1. What does cherry-pick create?

Practice exercise
  • On a branch, make two commits. Cherry-pick only the second one onto main.
  • Check that the hashes differ with git log --oneline --all.
Part 3Chapter 193 min read

Stash

Stash puts your unfinished work on a shelf so you can change branches with a clean working directory.

19.1 The problem

You are halfway through a change when a colleague asks for an urgent fix on another branch. Your work is not ready to commit, and Git refuses to switch because it would overwrite your edits. Stash solves exactly this.

19.2 Basic use

$ git stash
Saved working directory and index state WIP on feature: 8e4c1b7 Add form
$ git switch main

Your working directory is now clean. Do the urgent work, then come back.

$ git switch feature
$ git stash pop

pop re-applies the stashed changes and removes them from the stash.

19.3 Commands you will use

CommandWhat it does
git stash push -m "message"Stash with a helpful name
git stash listShow all stashes
git stash popRe-apply the newest stash and delete it
git stash applyRe-apply but keep it in the list
git stash dropDelete the newest stash
git stash show -pShow what the stash contains
git stash -uInclude untracked files
git stash branch nameCreate a branch from a stash
$ git stash list
stash@{0}: On feature: half-finished form
stash@{1}: WIP on main: a3b9d21 Fix typo
$ git stash apply stash@{1}

19.4 What stash does not include

By default stash saves changes to tracked files only. New files that Git has never seen stay behind unless you add -u. Ignored files need -a.

19.5 Conflicts when applying

If the branch changed since you stashed, pop can conflict. Resolve it like any merge conflict. After a conflict, Git keeps the stash, so nothing is lost.

19.6 Common mistakes

  • Stashing and forgetting. Stashes are easy to lose track of. Give each a message and clear them regularly.
  • Expecting new files to be stashed. Use -u.
  • Using stash as long-term storage. For work you want to keep, make a branch and commit.
Quick recap
  • git stash shelves uncommitted work; git stash pop brings it back.
  • Use -m to label stashes and -u for untracked files.
  • apply keeps the stash; pop removes it.
  • For long-lived work, commit on a branch instead.
Check yourself

1. Which command re-applies a stash and removes it from the list?

Practice exercise
  • Edit a file without committing, then stash it and check that git status is clean.
  • Switch branches, come back, and run git stash pop.
  • Create an untracked file and stash it with -u.
Part 3Chapter 203 min read

Tags

A tag is a permanent name for one commit, usually used to mark a release such as version 1.0.

20.1 Branches move, tags stay

A branch name follows new commits. A tag always points to the same commit, which makes it ideal for marking releases like v1.0.0.

20.2 Two kinds of tags

TypeWhat it isWhen to use
LightweightA simple name pointing at a commitQuick personal bookmarks
AnnotatedA full object with tagger, date and messageReleases you share
$ git tag v1.0.0-test
$ git tag -a v1.0.0 -m "First stable release"

Prefer annotated tags for anything public.

20.3 Working with tags

CommandWhat it does
git tagList tags
git tag -a v1.1.0 <hash> -m "msg"Tag an older commit
git show v1.0.0See the tag and its commit
git switch --detach v1.0.0Look at the project at that version
git tag -d v1.0.0-testDelete a local tag
C1 C2 C3 C4 v1.0.0 main
Tags mark fixed points while main moves on

20.4 Sharing tags

git push does not send tags by default. You send them on purpose.

$ git push origin v1.0.0
$ git push origin --tags
$ git push origin --delete v1.0.0

20.5 Version numbers

Most projects follow semantic versioning: MAJOR.MINOR.PATCH.

PartIncrease whenExample
MAJORYou make a breaking change1.4.2 to 2.0.0
MINORYou add a feature that stays compatible1.4.2 to 1.5.0
PATCHYou fix a bug1.4.2 to 1.4.3

On GitHub, a tag can become a Release, a page with notes and downloadable files for that version.

20.6 Common mistakes

  • Forgetting to push tags. Teammates cannot see them.
  • Moving a published tag. Others may already depend on it. Create a new tag instead.
  • Using lightweight tags for releases. They carry no message or date.
Quick recap
  • A tag names one commit permanently.
  • Use annotated tags (-a) for releases.
  • Push tags explicitly with git push origin <tag> or --tags.
  • Semantic versioning uses MAJOR.MINOR.PATCH.
Check yourself

1. Which version number comes after 1.4.2 when you add a compatible new feature?

Practice exercise
  • Create an annotated tag v0.1.0 on your latest commit.
  • Run git show v0.1.0 and read the output.
  • Make another commit, then confirm the tag still points to the older commit.
4

GitHub and Collaboration

Share your code, review other people's work and contribute to projects around the world.

Part 4Chapter 213 min read

Remotes and cloning

A remote is a copy of your repository stored somewhere else, usually on GitHub, and cloning is how you get one onto your machine.

21.1 What a remote is

So far everything lived on your computer. A remote is another copy of the repository on a server. Teammates push their work to it and pull each other's work from it. By tradition the main remote is called origin.

Local repository On your computer Remote (origin) On GitHub git push git fetch, git pull
Your local repository and its remote on GitHub

21.2 Creating a repository on GitHub

  1. Sign in at github.com and choose New repository.
  2. Enter a name such as hello-git and an optional description.
  3. Choose Public (anyone can see it) or Private (only people you invite).
  4. If you already have a local project, leave the options to add a README, .gitignore and licence unchecked, so the two do not clash.
  5. Select Create repository. GitHub then shows the commands you need.
Caution

Check the visibility before you create the repository. Anything pushed to a public repository can be seen and copied by anyone.

21.3 Connecting an existing local project

$ git remote add origin https://github.com/your-username/hello-git.git
$ git branch -M main
$ git push -u origin main

The first line registers the remote, the second makes sure your branch is called main, and the third uploads your history. The -u flag remembers the link, so later you can type only git push.

21.4 Cloning an existing repository

$ git clone https://github.com/your-username/hello-git.git
Cloning into 'hello-git'...
$ cd hello-git

Cloning downloads the full history, sets origin automatically and checks out the default branch. To use another folder name add it at the end: git clone <url> my-folder.

21.5 Inspecting remotes

CommandShows or does
git remote -vList remotes and their URLs
git remote add name urlAdd a remote
git remote rename old newRename a remote
git remote remove nameRemove a remote
git remote set-url origin <url>Change a remote's address
git branch -vvShow which remote branch each local branch follows
$ git remote -v
origin  https://github.com/your-username/hello-git.git (fetch)
origin  https://github.com/your-username/hello-git.git (push)

21.6 HTTPS or SSH

Every repository has two kinds of address.

FormLooks likeSign-in method
HTTPShttps://github.com/user/repo.gitToken or credential manager
SSHgit@github.com:user/repo.gitSSH key

Chapter 23 explains how to set up each one.

21.7 Common mistakes

  • Cloning inside another repository. Clone into a clean folder.
  • Adding a README on GitHub and also locally. The histories differ, and your first push is rejected. Create the repository empty instead.
  • Pushing to the wrong remote. Check git remote -v first.
Quick recap
  • A remote is another copy of the repository; the main one is called origin.
  • Create a repository on GitHub, then git remote add origin <url> and git push -u origin main.
  • git clone <url> copies a repository with its history.
  • Addresses come in HTTPS and SSH forms.
Check yourself

1. What is origin?

2. What does the -u flag do on the first push?

Practice exercise
  • Create an empty repository on GitHub named hello-git.
  • Connect your local project to it and push main.
  • Clone the repository into a second folder and check git log.
Part 4Chapter 224 min read

Push, pull and fetch

These three commands move commits between your computer and GitHub, and knowing how they differ avoids most beginner surprises.

22.1 Push: send your commits

$ git push
Enumerating objects: 5, done.
To https://github.com/your-username/hello-git.git
   3f2a9c1..9a1c4e7  main -> main

Push uploads commits that the remote does not have yet. After the first git push -u, a plain git push is enough.

22.2 Fetch: look without touching

$ git fetch
From https://github.com/your-username/hello-git
   9a1c4e7..b81e6d2  main       -> origin/main

Fetch downloads new commits but does not change your working files or your branch. They are stored in a remote-tracking branch named origin/main. You can inspect them before deciding what to do.

$ git log main..origin/main --oneline
b81e6d2 Add contact page

22.3 Pull: fetch and merge

git pull is a shortcut: it runs git fetch and then merges the result into your current branch.

origin/main Remote-tracking branch Local main Your branch Working files What you edit git merge updates
Pull is fetch plus merge
$ git pull
Updating 9a1c4e7..b81e6d2
Fast-forward
 contact.html | 8 ++++++++

Use git pull --rebase if you prefer a straight history (Chapter 17).

22.4 When a push is rejected

$ git push
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs
hint: Updates were rejected because the remote contains work that
hint: you do not have locally.

Someone else pushed before you. The fix is always the same: bring in their work first.

1 git pull Download and merge the remote changes 2 Resolve conflicts If any appear, fix them as in Chapter 16 3 Run your tests Make sure the combined code works 4 git push Now the push is accepted
Fixing a rejected push

22.5 Force pushing

$ git push --force-with-lease

A force push overwrites the remote history. You may need one after a rebase or an amend. Use --force-with-lease, which stops if someone else pushed in the meantime. Never force-push to main or any branch your team shares.

22.6 Other useful push commands

CommandPurpose
git push origin featurePush a named branch
git push -u origin featurePush a new branch and link it
git push origin --delete featureDelete a remote branch
git fetch --pruneRemove references to deleted remote branches
git pull --ff-onlyPull only if no merge is needed

22.7 Common mistakes

  • Pushing without pulling first. Make git pull a habit before you start work.
  • Using --force instead of --force-with-lease. The first can erase a teammate's commits.
  • Thinking fetch changes your files. It does not; only merge, rebase or pull do.
Quick recap
  • git push sends your commits; git fetch downloads without changing your files.
  • git pull is fetch plus merge (or rebase).
  • A rejected push means you must pull the remote work first.
  • Prefer --force-with-lease and never force-push shared branches.
Check yourself

1. Which command downloads new commits without changing your working files?

Practice exercise
  • In two clones of the same repository, push a commit from one and git fetch in the other.
  • Run git log main..origin/main to see the incoming commit, then git pull.
  • Create a rejected push on purpose and fix it with a pull.
Part 4Chapter 234 min read

Authentication: SSH keys and tokens

GitHub needs to know who you are before it accepts a push, and there are two safe ways to prove it: SSH keys and access tokens.

23.1 Why passwords no longer work

Since 2021 GitHub does not accept your account password for Git operations over HTTPS. You use either a personal access token or an SSH key. Both are safer, because they can be limited and revoked without changing your password.

23.2 Option 1: SSH keys

An SSH key is a pair of files. The private key stays secret on your computer. The public key is given to GitHub. GitHub uses the pair to check that you hold the private key, without the secret ever travelling.

1 Generate a key pair ssh-keygen creates a private and a public key file 2 Start the agent ssh-agent holds your unlocked key in memory 3 Add the private key ssh-add registers it with the agent 4 Copy the public key Paste it into GitHub under SSH and GPG keys 5 Test the connection ssh -T git@github.com
Setting up an SSH key
$ ssh-keygen -t ed25519 -C "you@example.com"
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/you/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3Nz...example you@example.com

Copy the whole line that starts with ssh-ed25519. On GitHub open Settings, then SSH and GPG keys, choose New SSH key, paste it and save.

$ ssh -T git@github.com
Hi your-username! You've successfully authenticated, but GitHub does not provide shell access.

Now use the SSH form of the address:

$ git remote set-url origin git@github.com:your-username/hello-git.git
Important

Share only the file ending in .pub. The file without .pub is your private key. Never email it, paste it in chat or commit it.

Add a passphrase when asked. It protects the key if your laptop is stolen.

23.3 Option 2: Personal access tokens

A token is a long random string that acts like a password with limited powers. GitHub offers two kinds. Fine-grained tokens can be limited to selected repositories and permissions, and GitHub recommends them where possible. Classic tokens use broad scopes such as repo.

  1. Open Settings, then Developer settings, then Personal access tokens.
  2. Create a token, choose the repositories and permissions, and set an expiry date.
  3. Copy it immediately; GitHub shows it only once.
  4. When Git asks for a password over HTTPS, paste the token.

Git Credential Manager, which comes with Git for Windows and is available on other systems, stores the token safely so you do not paste it every time.

23.4 Choosing between them

SSH keyAccess token (HTTPS)
Setup effortA few commands onceCreate and store a token
Day-to-dayNo promptsCredential manager remembers it
RevokeDelete the key on GitHubDelete or expire the token
Good forYour own laptopScripts, CI and restricted access

23.5 GitHub CLI shortcut

The GitHub command-line tool gh can handle the login for you.

$ gh auth login

23.6 Common mistakes

  • Committing a token or private key. Treat it as leaked and revoke it at once.
  • Using a token with far too many permissions. Give the minimum.
  • Mixing HTTPS and SSH remotes. An SSH key does nothing if your remote is an https:// address.
Quick recap
  • Use SSH keys or personal access tokens; passwords are no longer accepted.
  • Keep the private key secret and give GitHub only the .pub file.
  • Fine-grained tokens with expiry dates are safest.
  • ssh -T git@github.com tests an SSH setup.
Check yourself

1. Which file do you upload to GitHub for SSH access?

Practice exercise
  • Generate an ed25519 key with a passphrase and add the public key to GitHub.
  • Run ssh -T git@github.com and confirm the greeting.
  • Switch your remote to the SSH address and push a commit.
Part 4Chapter 243 min read

Forks

A fork is your own copy of someone else's repository on GitHub, which lets you propose changes to a project you do not own.

24.1 Why forks exist

You cannot push to a stranger's repository. A fork copies it into your account, where you have full control. You change your copy, then ask the owner to take your changes through a pull request (Chapter 25).

Upstream Original project on GitHub Your fork Your copy on GitHub Local clone On your computer Fork git clone git push Pull request
The fork workflow

24.2 Fork versus clone

ForkClone
Where it happensOn GitHub, copy to your accountOn your computer
Needs permissionNo, if the repository is publicNo, if you can read it
PurposeGet your own writable copy onlineGet files and history locally

You usually do both: fork on GitHub, then clone your fork.

24.3 Forking step by step

  1. Open the project's page and select Fork.
  2. Choose your account and create the fork.
  3. Clone your fork, not the original.
$ git clone git@github.com:your-username/project.git
$ cd project
$ git remote -v
origin  git@github.com:your-username/project.git (fetch)

24.4 Adding the upstream remote

The original repository is usually called upstream. Add it so you can pull in its new work.

$ git remote add upstream https://github.com/original-owner/project.git
$ git remote -v
origin    git@github.com:your-username/project.git (fetch)
upstream  https://github.com/original-owner/project.git (fetch)

24.5 Keeping your fork up to date

$ git fetch upstream
$ git switch main
$ git merge upstream/main
$ git push origin main

GitHub also has a Sync fork button on your fork's page that does the same thing without the command line.

Tip

Never work directly on your fork's main. Create a branch for each change, and keep main as a clean mirror of upstream.

24.6 Common mistakes

  • Cloning the original instead of your fork. You cannot push to it.
  • Forgetting to sync. Your changes drift away from the project and conflict later.
  • Forking when you are already a collaborator. If you have write access, a branch in the same repository is simpler.
Quick recap
  • A fork is your own online copy of another repository.
  • Clone your fork, and add the original as upstream.
  • Keep main in sync with git fetch upstream and a merge.
  • Work on branches, then open a pull request to the original.
Check yourself

1. Which repository should you clone to contribute to a project you do not own?

Practice exercise
  • Fork a practice repository, clone it, and add the upstream remote.
  • Run git remote -v and check you see both.
Part 4Chapter 253 min read

Pull requests

A pull request asks the project to take your branch, and it is where discussion, review and automatic checks happen before merging.

25.1 What a pull request is

A pull request (PR) is a proposal to merge one branch into another. It is a page on GitHub that shows the changes, hosts the discussion and runs automatic checks. Even on your own project, PRs are a good habit because they record why a change was made.

1 Create a branch Never work on main directly 2 Commit and push git push -u origin your-branch 3 Open the pull request Compare and pull request on GitHub 4 Review and discuss Teammates comment and request changes 5 Checks pass Automatic tests run on every update 6 Merge and clean up Merge, then delete the branch
The life of a pull request

25.2 Opening a pull request

$ git switch -c fix-typo
$ git add README.md
$ git commit -m "Fix typo in installation steps"
$ git push -u origin fix-typo
remote: Create a pull request for 'fix-typo' on GitHub by visiting:
remote:   https://github.com/your-username/hello-git/pull/new/fix-typo

GitHub shows a Compare and pull request button. On the form, write:

  • A clear title, like a good commit message.
  • A description of what changed and why, with screenshots if the change is visual.
  • Closing keywords such as Closes #12, which automatically close issue 12 when the PR merges.
  • Reviewers and assignees, if your team uses them.

25.3 Draft pull requests

Choose Create draft pull request when the work is not ready. A draft cannot be merged. It tells people you want early feedback, not a final review.

25.4 Reading a pull request page

TabShows
ConversationDescription, comments, review status and checks
CommitsEvery commit in the branch
ChecksResults of automatic tests and workflows
Files changedThe diff, where reviewers leave line comments

25.5 Three ways to merge

OptionResultBest for
Merge commitKeeps all commits and adds a merge commitPreserving full history
Squash and mergeCombines the branch into one commitTidy main with one commit per change
Rebase and mergeReplays commits on top, no merge commitA straight history with every commit kept

Repository owners can allow only the styles they prefer.

25.6 After the merge

$ git switch main
$ git pull
$ git branch -d fix-typo

GitHub offers a Delete branch button after merging. Use it to keep the branch list short.

25.7 Pull request templates

A file named .github/pull_request_template.md fills each new PR with a checklist, which helps authors remember tests and documentation.

## What does this change?

## How was it tested?

- [ ] Tests added or updated
- [ ] Documentation updated

25.8 Common mistakes

  • Huge pull requests. Reviewers skim them. Keep PRs small and focused.
  • No description. Explain the why, not just the what.
  • Pushing more commits after approval without telling anyone. New commits usually require a fresh review.
Quick recap
  • A pull request proposes merging a branch and hosts the review.
  • Write a clear title and description, and link issues with Closes #n.
  • Use draft PRs for early feedback.
  • Merge commit, squash and rebase are the three merge styles.
Check yourself

1. What does writing "Closes #12" in a pull request do?

Practice exercise
  • Create a branch, push it, and open a pull request in your own repository.
  • Merge it with Squash and merge, then delete the branch.
  • Run git pull locally to bring the merged result into main.
Part 4Chapter 263 min read

Code review

Review is where teammates catch bugs, share knowledge and keep quality high, and a kind, clear style makes it work.

26.1 Why review code

Another pair of eyes finds problems the author no longer sees. Review also spreads knowledge across the team, so no part of the project is understood by only one person.

26.2 How a review works on GitHub

Open Files changed. Hover over a line, select the + button and leave a comment. When you finish, choose Review changes and pick one of three options.

ChoiceMeaning
CommentGeneral feedback without approving or blocking
ApproveThe change is good to merge
Request changesThe author must address issues before merging

26.3 Suggested changes

Inside a comment, choose the Add a suggestion button. GitHub inserts a special block that you edit to hold the replacement text, for example:

total = price * quantity

The author accepts it with Commit suggestion, and GitHub makes the commit for them. Suggestions are ideal for typos and small fixes.

26.4 What to look for

AreaQuestions
CorrectnessDoes it do what the description says? Are edge cases handled?
TestsAre there tests, and do they pass?
ReadabilityAre names clear? Is anything too complicated?
SecurityAny secrets, unsafe input or risky permissions?
ScopeIs the change focused, or did unrelated edits slip in?

26.5 Writing helpful comments

  • Comment on the code, not the person: "This loop can skip the last item" rather than "You made a mistake".
  • Explain why, and offer an alternative when you can.
  • Label small preferences, for example "nit:" for style points that need not block merging.
  • Praise good work. It is part of a review too.

26.6 Receiving feedback

  • Assume good intent. Reviewers want the project to succeed.
  • Reply to every comment, even if only to say "Done".
  • Disagree politely with reasons, and ask questions if something is unclear.
  • Push fixes as new commits, then click Resolve conversation once addressed.

26.7 Requesting a review

Use the Reviewers panel on the right of the pull request. A file called CODEOWNERS (Chapter 33) can add the right reviewers automatically.

26.8 Common mistakes

  • Approving without reading. A rubber stamp helps nobody.
  • Rewriting the author's design in comments. Discuss big design questions before the code is written.
  • Waiting days to review. Slow feedback blocks the team. Aim to respond within a working day.
Quick recap
  • Reviews catch bugs and share knowledge.
  • Choose Comment, Approve or Request changes when you finish.
  • Be specific, kind and focused on the code.
  • Reply to comments and resolve conversations as you fix them.
Check yourself

1. Which review choice blocks a pull request until the author responds?

Practice exercise
  • Open a pull request in a practice repository with a friend, and leave three comments, one of them a suggestion.
  • Apply a suggestion as the author and resolve the conversation.
Part 4Chapter 273 min read

Issues, labels and projects

Issues record bugs and ideas, and projects arrange them into a board, so the whole team can see what is happening.

27.1 What an issue is

An issue is a discussion thread about a bug, a task or a feature request. It has a title, a description, comments, an assignee and labels. Issues are numbered, such as #12, and you can refer to them from commits and pull requests.

27.2 Writing a good issue

A good bug report lets someone reproduce the problem without asking questions.

Title: Login button does nothing on Safari

Steps to reproduce
1. Open the login page in Safari 17
2. Enter a valid email and password
3. Click "Log in"

Expected: the dashboard opens
Actual: nothing happens and no error appears

Environment: macOS 14, Safari 17.2

27.3 Labels, assignees and milestones

FeaturePurposeExample
LabelsCategorise issuesbug, enhancement, documentation, good first issue
AssigneesSay who is working on it@priya
MilestonesGroup issues for a release or deadlinev1.2.0
ProjectsShow issues on a boardTo do, In progress, Done

GitHub provides default labels, and you can add your own. The good first issue label is a convention that helps newcomers find easy tasks.

27.4 Linking issues and code

Mention an issue anywhere with #12. Use closing keywords in a pull request description or a commit message:

Fix login on Safari

Closes #12

The keywords close, fix and resolve, in their various forms, close the issue when the change reaches the default branch.

27.5 Mentions and references

  • @username notifies a person.
  • #12 links to an issue or pull request.
  • A full commit hash links to that commit.

27.6 GitHub Projects

A project is a board or table that collects issues and pull requests from one or more repositories. You can arrange them into columns such as Backlog, In progress, In review and Done, and add fields like priority or sprint.

Backlog Ideas and bugs to triage In progress Someone is working on it In review Open pull request Done Merged and closed start open PR merge
A simple project board flow

27.7 Issue templates

Files inside .github/ISSUE_TEMPLATE/ give reporters a form to fill in, which makes reports more complete.

27.8 Discussions

For open-ended questions and ideas that are not tasks, repositories can turn on Discussions, a forum-style space separate from issues.

27.9 Common mistakes

  • Vague issues like "it is broken". Add steps, expected and actual results.
  • Duplicates. Search before you open a new issue.
  • Issues without owners. Assign someone, or label them as available.
Quick recap
  • Issues track bugs, tasks and ideas; they are numbered and searchable.
  • Labels, assignees and milestones organise them.
  • Closes #n links a pull request to an issue and closes it on merge.
  • Projects show work as a board.
Check yourself

1. How do you link a pull request so that it closes issue 12 when merged?

Practice exercise
  • Open an issue in your practice repository using the bug-report layout above.
  • Add two labels, assign yourself, and create a three-column project board.
  • Reference the issue from a pull request with Closes #<number>.
Part 4Chapter 283 min read

GitHub Pages

GitHub Pages turns a repository into a free website, with no server to manage.

28.1 What Pages gives you

GitHub Pages hosts static sites made of HTML, CSS and JavaScript files. It is free, serves over HTTPS and updates every time you push. It is ideal for portfolios, project documentation and landing pages. It cannot run server-side code or a database, which is why this handbook's interactive parts all run in the browser.

28.2 Two kinds of site

TypeRepository nameAddress
User siteyour-username.github.iohttps://your-username.github.io/
Project siteany name, such as hello-githttps://your-username.github.io/hello-git/

28.3 Publishing your first page

1 Create a repository For example hello-git, public 2 Add index.html This is the page the site opens first 3 Push to GitHub git push origin main 4 Turn on Pages Settings, then Pages, then choose a branch and folder 5 Open the address The site appears after a minute or two
Publish a page in five steps
<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><title>My first page</title></head>
<body>
  <h1>Hello from GitHub Pages</h1>
</body>
</html>
$ git add index.html
$ git commit -m "Add home page"
$ git push origin main

In the repository, open Settings, choose Pages, and under Build and deployment pick Deploy from a branch. Select main and the / (root) folder, then save. GitHub shows the address when the deployment finishes.

28.4 Using GitHub Actions to deploy

If your site needs a build step, for example a React app or a static site generator, choose GitHub Actions as the source and add a workflow that builds the site and publishes the output. Chapter 31 introduces workflows.

28.5 Custom domains

In Settings, then Pages, you can enter your own domain. Create the matching DNS record at your domain registrar, and GitHub provides the HTTPS certificate.

28.6 Handy tips

  • Put images and styles in folders and link them with relative paths.
  • A file named 404.html becomes your custom error page.
  • A .nojekyll file turns off the default Jekyll processing, which helps with plain HTML projects that have folders starting with an underscore.

28.7 Common mistakes

  • Missing index.html. Pages shows a 404 without it.
  • Wrong path casing. File names are case sensitive on GitHub: Logo.png is not logo.png.
  • Expecting instant updates. A deployment can take a minute or two.
  • Putting secrets in a Pages repository. Everything published is public.
Quick recap
  • Pages hosts free static sites straight from a repository.
  • User sites live at username.github.io; project sites in a sub-path.
  • Enable it under Settings, then Pages.
  • Use Actions to build sites that need a build step.
Check yourself

1. What kind of site can GitHub Pages host?

Practice exercise
  • Publish a one-page site from a new repository and open its address.
  • Edit the heading, push, and watch the page update.
Part 4Chapter 293 min read

Repository hygiene

A well-kept repository welcomes newcomers and protects the project with a clear README, licence and contribution rules.

29.1 The README: the front door

The README is the first thing visitors see. GitHub displays it under the file list. A good README answers four questions in under a minute: What is this? How do I run it? How do I use it? How do I help?

# Project name

One sentence about what it does.

## Install
## Usage
## Contributing
## Licence

Add a screenshot, a short code example and badges for build status if you have them. Write in Markdown.

29.2 Markdown essentials

You typeYou get
# HeadingA large heading (## and ### make smaller ones)
**bold** and *italic*bold and italic text
- itemA bullet list
[text](https://example.com)A link
![alt](image.png)An image
Three backticksA code block

29.3 Choosing a licence

Without a licence, nobody has permission to reuse your code, even if it is public. Add a LICENSE file. GitHub can create one from a template when you add a file.

LicenceIn short
MITVery permissive. Reuse for anything, keep the copyright notice
Apache 2.0Permissive, with an explicit patent grant
GPL 3.0Reusers must also release their changes under the GPL

This is a simplified summary, not legal advice. For serious projects read the licence text or ask someone qualified.

29.4 Community files

FilePurpose
CONTRIBUTING.mdHow to report bugs, set up the project and send changes
CODE_OF_CONDUCT.mdHow people are expected to behave
SECURITY.mdHow to report a vulnerability privately
.github/ISSUE_TEMPLATE/Forms for new issues
.github/pull_request_template.mdChecklist for new PRs

GitHub shows these in the Community standards page of a repository and links them from the issue and PR screens.

29.5 Description, topics and social image

Fill in the one-line About description and add topics such as python or git-tutorial. Topics help people find your project in search.

29.6 A profile README

Create a public repository whose name is exactly your username, and add a README.md. GitHub shows it at the top of your profile, which is a good place for a short introduction and links to your best work.

29.7 Common mistakes

  • No licence. People cannot legally reuse the code.
  • A README that only says the project name. Explain installation and usage.
  • Committing generated files and secrets. Use .gitignore.
Quick recap
  • The README should explain what, how to run, how to use and how to contribute.
  • Add a LICENSE; MIT, Apache 2.0 and GPL 3.0 are common.
  • CONTRIBUTING.md, templates and a code of conduct welcome contributors.
  • A repository named after you becomes your profile README.
Check yourself

1. What happens if a public repository has no licence?

Practice exercise
  • Write a README for one of your repositories using the four-question outline.
  • Add an MIT LICENSE file from GitHub's template and a short CONTRIBUTING.md.
Part 4Chapter 303 min read

Contributing to open source

Open source runs on small contributions from strangers, and the workflow you have learned is exactly how they are made.

30.1 Why contribute

Contributing to open source teaches you to read real code, work with reviewers and communicate in public. Your commits and merged pull requests also become a visible record of your skills on your GitHub profile.

30.2 Finding a first project

  • Search GitHub issues with the label good first issue or help wanted.
  • Start with tools you already use, and look at their documentation for typos or gaps.
  • Check that the project is alive: recent commits, answered issues, and a CONTRIBUTING.md.

30.3 The complete workflow

1 Read the rules README, CONTRIBUTING and code of conduct 2 Pick or open an issue Say you would like to work on it and wait for a reply 3 Fork and clone Your fork on GitHub, a clone on your computer 4 Create a branch One branch per change, named clearly 5 Make the change and test Follow the project's style and run its tests 6 Commit and push Clear messages, push to your fork 7 Open the pull request Describe the change and link the issue 8 Respond to review Push fixes until it is approved and merged
From first look to merged pull request
$ git clone git@github.com:your-username/project.git
$ cd project
$ git remote add upstream https://github.com/owner/project.git
$ git switch -c fix-docs-typo
$ git add docs/install.md
$ git commit -m "Fix typo in installation guide"
$ git push -u origin fix-docs-typo

30.4 Small contributions count

You do not need to write a new feature. These are all welcome and valuable:

  • Correcting documentation, typos and broken links.
  • Adding a missing example.
  • Reproducing a bug and adding details to the issue.
  • Improving tests.
  • Translating text.

30.5 Good etiquette

  • Read the existing issues and pull requests first, so you do not duplicate work.
  • Ask before starting a large change.
  • Keep pull requests small and on topic.
  • Be patient. Maintainers are often volunteers.
  • Say thank you, and accept feedback gracefully.

30.6 When your pull request is not accepted

It happens, and it is not personal. The project may have a different direction. Ask what would make the change acceptable, learn from it, and try another issue.

30.7 Becoming a maintainer

Contributors who help regularly are sometimes invited to review and merge. As a maintainer, you will triage issues, review pull requests and keep documentation current, which makes your GitHub activity richer and more visible.

30.8 Common mistakes

  • Opening a pull request without reading the contribution guide. It may be closed quickly.
  • One giant pull request. Split it up.
  • Working on main in your fork. Always use a branch.
Quick recap
  • Look for good first issue labels and active projects.
  • Fork, clone, branch, change, push and open a pull request.
  • Documentation and test improvements are real contributions.
  • Be patient and respectful with maintainers.
Check yourself

1. Where should you make your changes in a fork?

Practice exercise
  • Find an open-source project with a good first issue label that interests you.
  • Read its CONTRIBUTING.md and write down the steps it asks for.
  • Send a small documentation fix as a pull request.
5

Advanced

Automate checks, recover lost work, tidy history and keep your repositories secure.

Part 5Chapter 313 min read

GitHub Actions

Actions runs your tests and scripts automatically whenever something happens in your repository, and it works as the engine of your whole workflow.

31.1 What Actions does

GitHub Actions is a built-in automation service. When an event occurs, such as a push or a pull request, GitHub starts a virtual machine and runs the commands you describe. The most common use is continuous integration (CI): every change is built and tested automatically, so mistakes show up in minutes.

Event push, pull request, schedule Workflow A YAML file in .github/workflows Job Runs on a fresh virtual machine triggers starts
How a workflow runs

31.2 The vocabulary

TermMeaning
WorkflowAn automated process defined in one YAML file
EventWhat starts the workflow: a push, a pull request, a timer
JobA group of steps that run on one machine; jobs can run in parallel
StepOne command, or one reusable action
RunnerThe machine that runs the job (for example ubuntu-latest)
ActionA reusable building block written by you or others

31.3 Your first workflow

Create the file .github/workflows/ci.yml in your repository.

name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - run: pip install -r requirements.txt
      - run: pytest

Reading it from top to bottom: run on every push to main and on every pull request; start an Ubuntu machine; fetch the code; install Python; install dependencies; run the tests.

Note

Action versions such as @v4 change over time. Check each action's page on the GitHub Marketplace for the newest major version before you copy a workflow.

$ git add .github/workflows/ci.yml
$ git commit -m "Add CI workflow"
$ git push

31.4 Watching it run

Open the Actions tab of your repository. Each run shows a green tick or a red cross. Click a run, then a job, to read the log of every step. On a pull request, the same result appears at the bottom as a check. A failed step stops the job. Fix the code, push again, and the workflow re-runs. You can also choose Re-run jobs on a run page.

31.5 YAML in two minutes

  • YAML uses spaces for nesting, never tabs. Two spaces is standard.
  • A line starting with - is a list item.
  • key: value pairs make a dictionary.
  • Quote values that could be misread, like "3.12", which would otherwise be read as the number 3.12.

31.6 Common mistakes

  • Wrong folder. Workflows must be in .github/workflows/.
  • Tab characters. They break YAML. Use spaces.
  • Forgetting actions/checkout. Without it, the runner has none of your files.
  • Misquoting versions. Python 3.10 unquoted becomes 3.1.
Quick recap
  • Actions runs workflows when events happen in your repository.
  • A workflow has jobs; a job has steps; steps run commands or actions.
  • Workflows live in .github/workflows/*.yml.
  • Results appear in the Actions tab and as checks on pull requests.
Check yourself

1. Where must workflow files be stored?

Practice exercise
  • Add the CI workflow above to a small project with one test.
  • Push, open the Actions tab and read the log.
  • Break the test on purpose, push, and watch the red cross appear.
Part 5Chapter 323 min read

Actions in practice

Matrices, secrets, caching and schedules turn a simple workflow into a dependable pipeline.

32.1 Test on several versions: matrix

A matrix runs the same job many times with different values.

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ["3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
      - run: pytest

Three parallel jobs appear, one per version.

32.2 Secrets

Never write passwords or API keys in a workflow file. Store them under Settings, then Secrets and variables, then Actions, and read them in the workflow.

steps:
  - run: ./deploy.sh
    env:
      API_TOKEN: ${{ secrets.API_TOKEN }}

GitHub hides secret values in the logs. Secrets are not passed to workflows triggered from forks, which protects you from malicious pull requests.

32.3 Caching dependencies

Many setup actions can cache downloads and make runs faster.

- uses: actions/setup-python@v5
  with:
    python-version: "3.12"
    cache: pip

32.4 Other triggers

TriggerStarts the workflow when...
pushCommits are pushed
pull_requestA pull request is opened or updated
scheduleA cron time arrives
workflow_dispatchSomeone clicks Run workflow
releaseA release is published
on:
  schedule:
    - cron: "0 3 * * 1"
  workflow_dispatch:

That runs every Monday at 03:00 UTC, and also gives you a manual Run workflow button.

32.5 Artifacts: keep the output

- uses: actions/upload-artifact@v4
  with:
    name: test-report
    path: reports/

Artifacts are files saved with a run, such as test reports or built packages, which you can download from the run page.

32.6 Deploying to GitHub Pages

permissions:
  contents: read
  pages: write
  id-token: write

The permissions block gives the workflow's built-in token only what it needs. Combined with the official Pages actions, it publishes your site after each push to main.

32.7 Writing safe workflows

  • Give the token the least permissions with a permissions: block.
  • Treat pull requests from forks as untrusted. Do not run their code with access to secrets.
  • Trust actions from verified creators, and pin important third-party actions to a full commit hash.

32.8 Common mistakes

  • Printing secrets in logs. Even masked values can leak when transformed.
  • Using pull_request_target carelessly. It can expose secrets to untrusted code.
  • Very slow workflows. Cache, run jobs in parallel and test only what changed.
Quick recap
  • A matrix repeats a job across versions or systems.
  • Store credentials as secrets, never in the YAML.
  • Triggers include push, pull request, schedule and manual runs.
  • Limit permissions and treat fork pull requests as untrusted.
Check yourself

1. Where should an API key used by a workflow be stored?

Practice exercise
  • Turn your CI workflow into a matrix across two language versions.
  • Add workflow_dispatch and run the workflow manually.
  • Add a secret and print only whether it exists, never its value.
Part 5Chapter 333 min read

Branch protection and CODEOWNERS

Protection rules make sure nothing reaches the main branch without review and passing checks, even by accident.

33.1 The problem

Rules in a document are easy to forget. Branch protection turns them into settings that GitHub enforces for everyone, including administrators if you choose.

33.2 Common rules

Open Settings, then Branches (or Rules, then Rulesets), and add a rule for main.

RuleWhat it enforces
Require a pull requestNo direct pushes to main
Require approvalsAt least one or two people must approve
Dismiss stale approvalsNew commits cancel old approvals
Require status checksChosen workflows must pass first
Require conversation resolutionAll review threads must be resolved
Require linear historyOnly squash or rebase merges are allowed
Block force pushesHistory cannot be rewritten
Block deletionsThe branch cannot be deleted
Require signed commitsCommits must carry a verified signature
Your branch Work happens here Checks and review Tests pass, approvals given Protected main Merge allowed open pull request merge
What a protected main branch demands

33.3 Rulesets

Rulesets are the newer, more flexible way to do this. They can target several branches or tags with patterns, can apply across an organisation, and can run in an evaluate mode first, which reports what would have been blocked without enforcing anything. Use them when you have more than a couple of rules.

33.4 CODEOWNERS

A file named CODEOWNERS assigns people or teams to parts of the codebase. When a pull request touches those files, GitHub asks the owners to review.

# Everything
*                  @your-username

# Documentation
/docs/             @docs-team

# Workflows need an admin's eye
/.github/workflows/ @your-username

Place the file in .github/, the root or docs/. With the rule Require review from Code Owners, no one can merge changes to those files without an owner's approval.

33.5 A sensible starting setup

  • Require a pull request with one approval.
  • Require the CI check to pass.
  • Block force pushes and deletions.
  • Add a CODEOWNERS file for sensitive paths.

33.6 Common mistakes

  • Requiring checks that never run. The pull request will wait forever. Make sure the check name matches your workflow job.
  • Too strict for a small team. Five required reviewers slows everyone. Match the rules to your team size.
  • Letting admins bypass rules routinely. The exception becomes the habit.
Quick recap
  • Protection rules enforce reviews and checks on important branches.
  • Require pull requests, approvals, status checks and no force pushes.
  • Rulesets are the modern, flexible alternative.
  • CODEOWNERS routes reviews to the right people.
Check yourself

1. What does requiring status checks do?

Practice exercise
  • Protect main in a practice repository so a pull request and a passing check are required.
  • Try to push directly to main and read the rejection message.
Part 5Chapter 343 min read

Git hooks

Hooks are small scripts that Git runs automatically at key moments, so mistakes are stopped before they reach the team.

34.1 What a hook is

A hook is a script that Git starts when something happens, such as just before a commit. If the script exits with an error, Git cancels the action. Hooks live in .git/hooks/.

$ ls .git/hooks
applypatch-msg.sample  pre-commit.sample  pre-push.sample  commit-msg.sample

Git ships samples ending in .sample. Remove the suffix to activate one.

34.2 Useful hooks

HookRunsTypical use
pre-commitBefore a commit is madeLint code, block secrets, run fast tests
commit-msgAfter you write a messageCheck message format
pre-pushBefore a pushRun the full test suite
post-mergeAfter a mergeReinstall dependencies

34.3 A simple pre-commit hook

This script refuses any commit that includes a file called .env.

#!/bin/sh
if git diff --cached --name-only | grep -q '^\.env$'; then
  echo "Blocked: .env must not be committed."
  exit 1
fi

Save it as .git/hooks/pre-commit and make it executable.

$ chmod +x .git/hooks/pre-commit
$ git add .env
$ git commit -m "Add settings"
Blocked: .env must not be committed.

34.4 Hooks are not shared

Everything inside .git stays on your machine, so teammates do not receive your hooks. Two common ways to share them:

  • Keep hooks in a folder in the repository and point Git at it: git config core.hooksPath .githooks.
  • Use a hook manager such as the pre-commit framework (Python), Husky (JavaScript) or lefthook.
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.6.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-added-large-files
$ pip install pre-commit
$ pre-commit install

From now on those checks run on every commit.

34.5 Skipping a hook

$ git commit --no-verify -m "Emergency fix"

Use this rarely. Anyone can bypass local hooks, so important rules should also exist in CI (Chapter 31) and branch protection (Chapter 33).

34.6 Common mistakes

  • Forgetting chmod +x. A hook that is not executable is silently ignored.
  • Slow hooks. If a commit takes thirty seconds, people will skip them. Keep pre-commit fast and put long tests in pre-push or CI.
  • Relying only on local hooks. They are a convenience, not security.
Quick recap
  • Hooks are scripts Git runs at set moments; a non-zero exit cancels the action.
  • pre-commit, commit-msg and pre-push are the most useful.
  • Hooks in .git/hooks are not shared; use core.hooksPath or a hook manager.
  • Back local hooks with CI checks.
Check yourself

1. A pre-commit hook exits with an error code. What happens?

Practice exercise
  • Write the .env blocking hook and test it.
  • Install the pre-commit framework and run it on all files with pre-commit run --all-files.
Part 5Chapter 353 min read

Reflog and recovery

Git rarely loses committed work, and the reflog is the diary that lets you find it again.

35.1 The safety net

You ran git reset --hard and your commits disappeared from git log. They are not truly gone. Git keeps a private diary, the reflog, of every place HEAD has pointed. As long as a commit appears in it, you can bring it back.

$ git reflog
9a1c4e7 HEAD@{0}: reset: moving to HEAD~2
b81e6d2 HEAD@{1}: commit: Add search
3f2a9c1 HEAD@{2}: commit: Add login

Entry HEAD@{1} is the commit that the reset made unreachable.

C1 C2 C3 (lost) main HEAD
Reset moved main back, but the reflog still remembers C3

35.2 Recovering a lost commit

$ git switch -c rescue b81e6d2
$ git reset --hard b81e6d2

Creating a branch at the old hash is the safest form, because it adds a label to the commit without moving anything else. You can also reset the current branch back to the entry shown by the reflog:

$ git reset --hard HEAD@{1}

35.3 Typical rescue stories

SituationWhat to do
Reset too farFind the old tip in git reflog and reset to it
Deleted a branch by mistakeFind its last commit in the reflog and git switch -c name <hash>
Bad rebaseFind the entry before the rebase started and reset to it
Commits made in a detached HEADThe reflog lists them; create a branch at the hash

35.4 Per-branch reflog

$ git reflog show feature

Each branch also has its own history of movements.

35.5 How long entries last

Reflog entries are kept for a limited time, by default about 90 days for reachable entries and 30 days for unreachable ones, after which Git's clean-up can remove them. Recover work soon rather than later.

35.6 When the reflog is not enough

Work that was never committed is not in the reflog. A file you edited and discarded with git restore cannot be recovered by Git. Commit early and often to give Git something to remember. For objects not reachable even from the reflog, git fsck --lost-found can list dangling commits, which is a last resort.

35.7 Common mistakes

  • Panicking and running more commands. Stop and read the reflog first.
  • Expecting to recover uncommitted work. Git cannot restore what it never saw.
  • Waiting weeks. Old unreachable entries are eventually cleaned up.
Quick recap
  • The reflog records where HEAD and branches pointed.
  • Find the lost commit hash in git reflog, then create a branch at it.
  • Entries expire after a while, so act soon.
  • Uncommitted work cannot be recovered from the reflog.
Check yourself

1. You ran git reset --hard and lost commits. What should you try first?

Practice exercise
  • Make three commits, reset hard back two, then recover them using git reflog.
  • Delete a branch with -D and bring it back.
Part 5Chapter 363 min read

Bisect and interactive rebase

Bisect finds the commit that introduced a bug, and interactive rebase lets you polish your commits before you share them.

36.1 git bisect: find the bad commit

Suppose a bug appeared somewhere in the last 200 commits. Checking each would take hours. Bisect performs a binary search, halving the range each time, so about eight checks are enough for 200 commits.

1 Start git bisect start 2 Mark the broken state git bisect bad 3 Mark a known good commit git bisect good <hash> 4 Test what Git checks out Answer good or bad each time 5 Read the verdict Git names the first bad commit 6 Finish git bisect reset
Bisecting for a bug
$ git bisect start
$ git bisect bad
$ git bisect good v1.2.0
Bisecting: 97 revisions left to test after this (roughly 7 steps)
$ git bisect good
$ git bisect bad
b81e6d2 is the first bad commit
$ git bisect reset

36.2 Automating bisect

If you have a test that fails on the bug, let Git run it.

$ git bisect start HEAD v1.2.0
$ git bisect run pytest tests/test_checkout.py

Git repeats the test at each step and reports the first failing commit by itself.

36.3 Interactive rebase: polish history

Before opening a pull request you may want to merge small "fix typo" commits or reword unclear messages. Interactive rebase does that on your own, unshared commits.

$ git rebase -i HEAD~4

An editor opens with a list, oldest commit first.

pick 3f2a9c1 Add login form
pick 8e4c1b7 Fix typo
pick a3b9d21 Add validation
pick 7b1d2e4 Fix validation bug

Change the word at the start of each line to say what to do.

CommandEffect
pickKeep the commit as it is
rewordKeep it but change the message
editStop so you can change the commit's content
squashMerge into the previous commit and combine the messages
fixupMerge into the previous commit and discard this message
dropDelete the commit
pick 3f2a9c1 Add login form
fixup 8e4c1b7 Fix typo
pick a3b9d21 Add validation
fixup 7b1d2e4 Fix validation bug

Save and close. Four commits become two clean ones. You can also reorder commits by moving their lines.

36.4 Fixup commits

$ git commit --fixup 3f2a9c1
$ git rebase -i --autosquash HEAD~5

--fixup records a correction aimed at an earlier commit, and --autosquash arranges the list for you.

36.5 Safety

Caution

Interactive rebase rewrites history, so use it only on commits that nobody else has. If something goes wrong, run git rebase --abort, or recover through the reflog (Chapter 35).

36.6 Common mistakes

  • Rebasing shared commits. The golden rule from Chapter 17 applies.
  • Marking the first line as squash. There is no earlier commit to merge into.
  • Not knowing a good commit for bisect. Use a release tag or an older commit that you know worked.
Quick recap
  • git bisect binary-searches history to find the commit that introduced a bug.
  • git bisect run <command> automates the search.
  • git rebase -i lets you reword, squash, fixup, drop and reorder commits.
  • Only rewrite history that is still private.
Check yourself

1. Roughly how many tests does bisect need to search 1,000 commits?

Practice exercise
  • Make four small commits, then squash the middle two with git rebase -i.
  • Introduce a bug on purpose and find it with git bisect.
Part 5Chapter 373 min read

Submodules, monorepos and large files

Big projects need tools for sharing code between repositories and storing large files, and each has trade-offs.

37.1 Submodules: a repository inside a repository

A submodule pins another repository at an exact commit inside yours. It is useful when you depend on a shared library that lives in its own repository.

$ git submodule add https://github.com/example/shared-lib.git libs/shared-lib
$ git commit -m "Add shared-lib as a submodule"

Git records the submodule's address in .gitmodules and the commit it points to. Cloning needs one more flag, or the folder will be empty.

$ git clone --recurse-submodules https://github.com/you/app.git
$ git submodule update --init --recursive
$ git submodule update --remote
ProsCons
Exact, reproducible version of the dependencyExtra steps for every clone and update
Library stays in one placeEasy to forget to commit the new pointer

Often a package manager (pip, npm, Maven) is simpler for libraries. Consider submodules when you need the source and its history together.

37.2 Monorepo or many repositories

MonorepoMany repositories
StructureAll projects in one repositoryOne repository per project
Sharing codeEasy, one commit can change several partsNeeds published packages
PermissionsHarder to restrict one partPer-repository access
ScaleNeeds tooling as it growsMany repositories to manage
Used byLarge engineering teams with strong toolingMost small teams

Very large repositories can use sparse checkout, which downloads only some folders, and partial clone, which downloads file contents on demand.

$ git clone --filter=blob:none https://github.com/example/big-repo.git
$ git sparse-checkout set services/api

37.3 Large files and Git LFS

Git stores every version of every file forever, so large binary files such as videos, datasets and design files make a repository huge. GitHub warns about files over 50 MB and blocks files over 100 MB. Git LFS (Large File Storage) keeps lightweight pointer files in Git and stores the real content on a separate server.

$ git lfs install
$ git lfs track "*.psd"
$ git add .gitattributes
$ git add design.psd
$ git commit -m "Add design file with LFS"

Tracking rules are saved in .gitattributes, which you commit.

Warning

Track files with LFS before committing them. Files already in history stay there and keep the repository large. Moving them later needs git lfs migrate, which rewrites history.

GitHub gives each account a limited LFS storage and bandwidth allowance, so check the current limits for your plan. Datasets that change often are better kept in dedicated tools for data versioning or in cloud storage.

37.4 Common mistakes

  • Cloning a repository with submodules and getting empty folders. Use --recurse-submodules.
  • Committing large datasets to normal Git. Use LFS or external storage.
  • Moving to a monorepo without build tooling. Builds and tests become slow.
Quick recap
  • Submodules pin another repository at a specific commit.
  • Clone with --recurse-submodules.
  • Monorepos suit big teams with tooling; separate repositories suit most others.
  • Use Git LFS for large binary files, and set it up before committing them.
Check yourself

1. Why is the folder of a submodule empty after a normal clone?

Practice exercise
  • Add a small public repository as a submodule and clone your project with --recurse-submodules.
  • Track *.zip files with LFS in a practice repository.
Part 5Chapter 384 min read

Security: secrets, Dependabot and signed commits

One leaked password can undo a project, so build safe habits and let GitHub's automatic tools watch for you.

38.1 Rule one: secrets do not belong in Git

Passwords, API keys, tokens and private keys must never be committed. Even if you delete the file later, the secret remains in the history, and public repositories are scanned by bots within minutes.

38.2 If you leak a secret

1 Revoke the secret Cancel or rotate the key at the provider first 2 Create a new one Store it as an environment variable or secret 3 Remove it from history Use git filter-repo or the BFG tool 4 Force-push the clean history Tell collaborators to re-clone 5 Check for misuse Review the provider's access logs
Respond in this order

Revoking comes first because anyone may already have copied the secret. Cleaning history is a second, optional step.

38.3 Keeping secrets out

  • Put them in a .env file that is listed in .gitignore, and commit a .env.example with fake values.
  • Use your platform's secret store: GitHub Actions secrets, a cloud key vault or a password manager.
  • Turn on secret scanning and push protection in your repository's security settings, which block pushes that contain recognised secrets.
  • Add a pre-commit hook that scans for secrets (Chapter 34).

38.4 Dependabot

Dependabot watches your dependencies.

FeatureWhat it does
Dependabot alertsWarns when a dependency has a known vulnerability
Dependabot security updatesOpens a pull request with the fix
Dependabot version updatesOpens regular pull requests to keep dependencies current
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"

38.5 Code scanning

Code scanning with CodeQL analyses your source for common vulnerability patterns and reports them on pull requests. It is free for public repositories and available for private ones on some plans.

38.6 Protect your account

  • Use a strong, unique password in a password manager.
  • Turn on two-factor authentication. GitHub requires it for people who contribute code.
  • Consider passkeys or hardware security keys.
  • Review Settings, then Sessions and SSH keys now and then, and remove what you do not recognise.

38.7 Signed commits

Anyone can set any name and email in Git, so a commit's author is not proof of identity. A signature proves that the commit came from the holder of a key. GitHub marks such commits Verified. Git can sign with an SSH key, which you may already have from Chapter 23.

$ git config --global gpg.format ssh
$ git config --global user.signingkey ~/.ssh/id_ed25519.pub
$ git config --global commit.gpgsign true

Add the same public key in GitHub under SSH and GPG keys, choosing the type Signing key.

38.8 Report vulnerabilities properly

A SECURITY.md file tells visitors how to report a problem privately. GitHub also offers private vulnerability reporting, so researchers do not post exploits in public issues.

38.9 Common mistakes

  • Thinking a private repository is safe for secrets. Access changes, repositories get forked and leaked.
  • Deleting the file and calling it fixed. The history still has it.
  • Ignoring Dependabot pull requests. Old, vulnerable dependencies are a common way in.
Quick recap
  • Never commit secrets; use .gitignore, secret stores and push protection.
  • If one leaks, revoke it first, then clean history.
  • Dependabot and code scanning find vulnerable dependencies and code.
  • Use two-factor authentication and sign your commits.
Check yourself

1. You pushed an API key by mistake. What is the FIRST step?

Practice exercise
  • Create .env.example and add .env to .gitignore in a practice project.
  • Add a dependabot.yml file and enable secret scanning in the repository settings.
  • Set up SSH commit signing and look for the Verified badge on GitHub.
6

Practice and Reference

Choose a team workflow, avoid common mistakes, and keep a cheat sheet, interview questions and glossary close at hand.

Part 6Chapter 394 min read

Branching strategies

A branching strategy is the team's agreement on how branches are named, used and merged, and the right one depends on how often you release.

39.1 Why you need one

Git lets you branch in any way you like, which is exactly the problem. Without an agreement, every developer does something different, and merging becomes painful. A strategy gives everyone the same map.

39.2 GitHub Flow

The simplest model, used by many web teams. main is always ready to deploy. All work happens on short-lived branches that are merged by pull request.

C1 C2 F1 M1 F2 M2 main
GitHub Flow: short branches that merge back into main quickly
1 Branch from main Name it for the work, such as fix-login 2 Commit and push Small, clear commits 3 Open a pull request Discuss and review 4 Pass the checks Tests and review must succeed 5 Merge and deploy main is released, the branch is deleted
GitHub Flow in five steps

39.3 Git Flow

A heavier model for software with versions and scheduled releases, such as mobile apps and libraries. It has permanent branches (main and develop) and temporary ones (feature, release, hotfix).

v1.0 D1 F1 F2 D2 v1.1 v1.0 v1.1 develop
Git Flow: features merge into develop, and releases flow into main
BranchPurpose
mainReleased code only, tagged with versions
developIntegration of finished features
feature/*One feature each, branched from and merged back into develop
release/*Final fixes before a release
hotfix/*Urgent fixes branched from main

39.4 Trunk-based development

Everyone works on one shared branch, the trunk (main). Changes are tiny and merged at least daily, directly or through very short-lived branches. Unfinished features are hidden behind feature flags, switches that turn code on or off without a new deployment. It is the style used by many large teams that deploy continuously, and it relies on strong automated tests.

39.5 Comparing them

GitHub FlowGit FlowTrunk-based
Long-lived branchesmainmain, developmain
Branch lifetimeDaysDays to weeksHours to a day
Release styleContinuousScheduled versionsContinuous
ComplexityLowHighLow, but needs discipline
Needs strong CIYesHelpfulEssential
Best forWeb apps and small teamsPackaged software with versionsMature teams that deploy often

39.6 How to choose

  • Deploy several times a week? Start with GitHub Flow.
  • Ship numbered versions and support older ones? Consider Git Flow, or a simplified release-branch version of it.
  • Have excellent tests and an experienced team? Try trunk-based development.

39.7 Common mistakes

  • Choosing Git Flow because it looks professional. It adds overhead that small teams do not need.
  • Long-lived feature branches. The longer a branch lives, the worse the conflicts.
  • Having a strategy nobody wrote down. Put it in CONTRIBUTING.md.
Quick recap
  • A branching strategy is a shared agreement on how work flows.
  • GitHub Flow: short branches and always-deployable main.
  • Git Flow: develop, release and hotfix branches for versioned software.
  • Trunk-based: tiny, frequent merges and feature flags.
Check yourself

1. Which strategy fits a web app that deploys several times a day?

Practice exercise
  • Write a short branching policy for your team and add it to CONTRIBUTING.md.
  • Practise one full GitHub Flow cycle: branch, commit, pull request, merge, delete.
Part 6Chapter 403 min read

Team best practices

Good habits make a repository pleasant for everyone, and most of them take only a few seconds.

40.1 Commits

  • Commit small and often; each commit does one thing.
  • Write messages in the imperative: "Add", "Fix", "Remove".
  • Never commit secrets, generated files or large binaries.
  • Make sure the project builds and the tests pass at every commit when you can.

40.2 Conventional commits

Many teams add a short type prefix, which helps tools generate change logs and version numbers.

PrefixUse forExample
featA new featurefeat: add password reset
fixA bug fixfix: handle empty cart
docsDocumentation onlydocs: explain install steps
refactorCode restructuring without behaviour changerefactor: split payment module
testAdding or fixing teststest: cover login errors
choreTooling and maintenancechore: update dependencies

40.3 Branches

  • Name branches by purpose: feature/search, fix/login-timeout.
  • Keep them short-lived and delete them after merging.
  • Update from main regularly to avoid giant conflicts.

40.4 Pull requests

  • Keep them small. A few hundred changed lines at most is a good target.
  • Explain what and why, and link the issue.
  • Run the tests yourself before asking for review.
  • Review your own pull request first; you will catch things.

40.5 Reviews

  • Respond within a working day.
  • Be kind, specific and constructive (Chapter 26).
  • Authors fix; reviewers do not push to someone else's branch without asking.

40.6 Repository settings

  • Protect main and require reviews and checks (Chapter 33).
  • Keep a clear README, CONTRIBUTING.md and .gitignore.
  • Turn on Dependabot and secret scanning (Chapter 38).
  • Use one line-ending policy through .gitattributes.
# .gitattributes
* text=auto
*.sh text eol=lf

40.7 Onboarding a new teammate

1 Install and configure Git Name, email and default branch 2 Set up access SSH key or token and two-factor authentication 3 Clone the project Run it and run the tests 4 Read the guide README and CONTRIBUTING 5 Make a first small change A typo fix through a real pull request
A one-hour Git onboarding

40.8 Common mistakes

  • Different habits for each person. Write the rules down once.
  • Huge, rare merges. Integrate small and often.
  • Skipping reviews under pressure. That is exactly when bugs slip in.
Quick recap
  • Small, clear commits and focused pull requests keep history readable.
  • Conventional commit prefixes help automation.
  • Protect main, review quickly and keep documentation current.
  • A simple onboarding path gets newcomers productive fast.
Check yourself

1. What is a good size for a pull request?

Practice exercise
  • Add a conventional-commits section and a pull request checklist to your team's CONTRIBUTING.md.
  • Write the onboarding steps for your team and test them with a new joiner.
Part 6Chapter 413 min read

Common mistakes and fixes

Everyone makes the same Git mistakes, and almost all of them have a short, safe fix.

41.1 I committed on the wrong branch

You meant to work on a feature branch but committed on main, and have not pushed yet.

$ git branch feature-x
$ git reset --hard origin/main
$ git switch feature-x

The first line keeps your commits on a new branch, the second moves main back to match the remote, and the third takes you to your work.

41.2 I want to undo my last commit but keep the changes

$ git reset --soft HEAD~1

41.3 I forgot a file in the last commit

$ git add forgotten.txt
$ git commit --amend --no-edit

41.4 I need to undo a merge

$ git merge --abort
$ git reset --hard ORIG_HEAD
$ git revert -m 1 <merge-hash>

Use the first when the merge is still in progress, the second right after a merge you have not pushed, and the third for a merge that is already pushed.

41.5 I committed a file that should be ignored

$ git rm --cached secrets.txt
$ echo "secrets.txt" >> .gitignore
$ git commit -am "Stop tracking secrets.txt"

If it held a real secret, follow Chapter 38.

41.6 Error messages and what they mean

MessageMeaning and fix
fatal: not a git repositoryYou are in the wrong folder. cd into the project
error: failed to push some refsThe remote has new work. Run git pull, then push
Permission denied (publickey)GitHub does not accept your SSH key. Check ssh -T git@github.com and ssh-add -l
Authentication failedUse a personal access token or SSH; passwords are not accepted
refusing to merge unrelated historiesTwo histories share no common commit. On stage 3, do not add --allow-unrelated-histories and do not merge origin/greeting-a or origin/greeting-b. Create both branches from main. Elsewhere, use the flag once, knowingly, only when you mean to join two separate repositories
src refspec main does not match anyThere is no commit yet, or your branch has another name. Commit, then git branch -M main
Your local changes would be overwrittenCommit or git stash before switching or pulling
CONFLICT (content)Fix the markers, git add, then commit or --continue (Chapter 16)
detached HEADYou are on a commit, not a branch. git switch -c name keeps your work
warning: LF will be replaced by CRLFLine-ending difference. Set core.autocrlf (Chapter 5)
remote: error: File is 120 MBGitHub blocks files over 100 MB. Use Git LFS (Chapter 37)

41.7 I think I lost my work

Do not panic and do not run more commands blindly. Run git reflog, find the commit, and create a branch at it (Chapter 35). Uncommitted edits are the only thing Git cannot return.

41.8 Safety habits

  • Run git status before and after every important command.
  • Commit often so there is something to go back to.
  • Create a backup branch before a risky operation: git branch backup.
  • Use --dry-run or -n where a command offers it.
  • Prefer --force-with-lease to --force.
Quick recap
  • Most mistakes can be fixed with reset, revert, amend or the reflog.
  • Read error messages: they usually name the fix.
  • git status and a backup branch make risky work safe.
  • Uncommitted work cannot be recovered, so commit often.
Check yourself

1. You committed to main by mistake and have not pushed. What keeps your work safe?

Practice exercise
  • Practise the wrong-branch fix in a throwaway repository.
  • Cause a rejected push and a merge conflict on purpose, and fix both.
Part 6Chapter 423 min read

Cheat sheet

One place to look up the commands you use most, grouped by what you want to do.

42.1 Setup and configuration

CommandPurpose
git config --global user.name "Name"Set your name
git config --global user.email "mail"Set your email
git config --global init.defaultBranch mainDefault branch name
git config --listShow settings

42.2 Starting a repository

CommandPurpose
git initCreate a repository here
git clone <url>Copy a remote repository
git remote add origin <url>Connect a remote

42.3 Snapshots

CommandPurpose
git statusShow what changed
git add <file> / git add .Stage changes
git add -pStage part of a file
git commit -m "msg"Commit what is staged
git commit --amendFix the last commit
git rm <file> / git mv a bDelete or rename a file

42.4 Inspecting

CommandPurpose
git log --oneline --graph --allCompact history graph
git show <commit>One commit in detail
git diff / git diff --stagedUnstaged / staged changes
git blame <file>Who changed each line
git reflogWhere HEAD has been

42.5 Branching and merging

CommandPurpose
git branchList branches
git switch -c <name>Create and switch
git switch <name>Switch
git merge <branch>Merge into the current branch
git rebase <branch>Replay commits on another branch
git cherry-pick <hash>Copy one commit
git branch -d <name>Delete a merged branch

42.6 Remotes

CommandPurpose
git fetchDownload without merging
git pull / git pull --rebaseFetch and merge or rebase
git push / git push -u origin <branch>Upload commits
git push --force-with-leaseSafer force push
git remote -vList remotes

42.7 Undoing

CommandPurpose
git restore <file>Discard working changes
git restore --staged <file>Unstage
git reset --soft HEAD~1Undo commit, keep changes staged
git reset --hard HEAD~1Undo commit and discard changes
git revert <commit>Undo with a new commit
git clean -nPreview removal of untracked files

42.8 Shelving and marking

CommandPurpose
git stash / git stash popShelve and restore work
git stash -uInclude untracked files
git tag -a v1.0.0 -m "msg"Annotated tag
git push origin --tagsPush tags

42.9 Advanced

CommandPurpose
git rebase -i HEAD~nEdit the last n commits
git bisect startFind a bug by binary search
git submodule update --init --recursiveFetch submodules
git lfs track "*.psd"Store large files with LFS

42.10 Symbols worth knowing

SymbolMeaning
HEADThe commit you are on
HEAD~1One commit before HEAD
origin/mainYour copy of the remote main branch
main..featureCommits in feature that are not in main
.The current folder
Quick recap
  • Bookmark this chapter for quick lookups.
  • Learn the groups: setup, snapshots, branches, remotes, undo.
  • When unsure, git status and git log --oneline --graph --all tell you where you are.
Practice exercise
  • Print this chapter or keep it open while you work for one week.
  • Pick five commands you do not yet use and try each once.
Part 6Chapter 435 min read

Interview questions

These questions come up again and again in developer interviews, with short answers you can explain in your own words.

Tap a question to see a model answer. Try answering aloud first.

43.1 Basics

What is the difference between Git and GitHub?

Git is a free, distributed version control tool that runs on your computer. GitHub is an online service that hosts Git repositories and adds collaboration features such as pull requests, issues and Actions.

What is a commit?

A commit is a snapshot of the staged project files with an author, date, message and a link to its parent commit. It is identified by a hash.

Explain the three areas in Git.

The working directory holds the files you edit, the staging area holds the changes chosen for the next commit, and the repository stores the committed history in the .git folder.

What is the difference between git fetch and git pull?

Fetch downloads new commits and updates remote-tracking branches without changing your files. Pull runs fetch and then merges (or rebases) the result into your current branch.

What does git clone do compared with git fork?

Clone copies a repository, with its history, to your computer. A fork is a copy of a repository in your own GitHub account, used to propose changes to projects you do not own.

What is HEAD?

HEAD is a pointer to your current position, usually the branch you are on, which in turn points to its latest commit.

43.2 Branching and merging

What is a branch, and why are branches cheap in Git?

A branch is a movable pointer to a commit. Creating one only writes a tiny file with a hash, so it is instant and uses almost no space.

What is the difference between merge and rebase?

Merge joins two histories with a merge commit and keeps the real branching shape. Rebase replays your commits on top of another branch, creating new commits and a linear history.

When should you not rebase?

Never rebase commits that are already shared with others, because it rewrites history and breaks their copies.

What is a fast-forward merge?

When the target branch has no new commits, Git just moves its pointer forward to the other branch's tip, without creating a merge commit.

How do you resolve a merge conflict?

Open the conflicted files, choose or combine the correct content, remove the conflict markers, git add the files, then commit or run the continue command.

What does git cherry-pick do?

It copies one or more specific commits onto the current branch, creating new commits with new hashes.

What is git stash used for?

It temporarily shelves uncommitted changes so you can switch tasks with a clean working directory, and you bring them back later with git stash pop.

43.3 Undoing and recovery

What is the difference between git reset and git revert?

Reset moves the branch pointer back and rewrites history, so it is for local commits. Revert adds a new commit that cancels an earlier one, so it is safe for shared history.

Explain reset --soft, --mixed and --hard.

All three move the branch. Soft keeps changes staged, mixed (the default) unstages them but keeps the files, and hard also discards the file changes.

How would you recover a commit you lost after a hard reset?

Run git reflog to find the commit hash, then create a branch at that hash or reset to it.

How do you undo the last commit but keep the work?

git reset --soft HEAD~1 if it is not pushed. If it is pushed, use git revert instead.

You committed a password. What do you do?

Revoke and replace the password immediately. Then remove it from history with a tool such as git filter-repo, force-push, and ask collaborators to re-clone.

43.4 GitHub and teamwork

What is a pull request, and why use one?

A pull request proposes merging one branch into another and hosts review, discussion and automated checks before the code reaches the main branch.

What are the merge options on a pull request?

Merge commit keeps all commits plus a merge commit, squash and merge combines the branch into one commit, and rebase and merge replays the commits without a merge commit.

What is GitHub Actions?

A built-in automation service that runs workflows, defined in YAML files, in response to events such as pushes and pull requests, commonly for continuous integration and deployment.

What is branch protection?

Repository rules that stop risky actions on important branches, such as pushing directly, force-pushing or merging without approvals and passing checks.

Describe a good Git workflow for a team.

Branch from main for each change, commit small and clearly, open a pull request, get a review and passing checks, merge, delete the branch. Protect main and keep branches short-lived.

How do SSH keys work with GitHub?

You keep a private key on your computer and give GitHub the public key. GitHub verifies that you hold the private key without it ever being sent.

What is .gitignore?

A file listing patterns of files Git should not track, such as secrets, dependencies and build output.

What are tags used for?

Tags permanently name a commit, usually to mark a release such as v1.0.0.

Quick recap
  • Be ready to explain the three areas, merge versus rebase and reset versus revert.
  • Describe a team workflow from branch to pull request to merge.
  • Know how to recover lost work with the reflog.
Practice exercise
  • Answer five questions aloud without looking, then check the model answers.
  • Ask a friend to quiz you on the undo commands.
Part 6Chapter 443 min read

Glossary

Plain-language definitions of the terms used in this handbook.

44.1 Terms

TermMeaning
ActionA reusable step used in a GitHub Actions workflow
AmendTo replace the most recent commit with a new one
ArtifactA file saved from a workflow run, such as a report
BisectBinary search through history to find the commit that introduced a bug
BlameA view showing who last changed each line of a file
BranchA movable pointer to a commit; a line of work
CheckoutTo switch branches or restore files (older command, now partly switch and restore)
Cherry-pickCopy a single commit onto another branch
CI/CDContinuous integration and delivery: automatic building, testing and deploying
CloneA full copy of a repository, including history
CommitA saved snapshot with message, author and parent
ConflictA merge problem where both sides changed the same lines
DependabotGitHub's tool for dependency alerts and update pull requests
Detached HEADHEAD pointing straight at a commit instead of a branch
DiffA comparison showing added and removed lines
Fast-forwardA merge that only moves a pointer, with no new commit
FetchDownload remote commits without changing your files
ForkYour own GitHub copy of someone else's repository
HEADPointer to your current branch or commit
HookA script Git runs at a set moment, such as before a commit
IndexAnother name for the staging area
IssueA tracked bug, task or request on GitHub
LFSLarge File Storage, for big binary files
MainThe conventional name of the default branch
MergeCombine the work of two branches
MonorepoOne repository holding many projects
OriginThe default name of the main remote
PullFetch and merge in one step
Pull requestA proposal to merge a branch, with review and checks
PushUpload commits to a remote
RebaseReplay commits on top of another base
ReflogLocal diary of where HEAD and branches have pointed
RemoteA repository copy hosted elsewhere
RepositoryA project and its complete history
RevertCreate a commit that cancels an earlier one
SquashCombine several commits into one
Staging areaWhere changes wait to be included in the next commit
StashA shelf for unfinished changes
SubmoduleA repository nested inside another at a fixed commit
TagA permanent name for a commit
UpstreamThe original repository you forked, or the remote branch a local branch follows
Working directoryThe files you see and edit
Note

You have reached the end of the handbook. The best next step is practice. Build a small project, open a pull request, review someone else's, and contribute to an open-source project you like.