Back to All Articles
Notes39 min read

Git & GitHub, Explained Simply - Backbencher codes

Learn how to save your code, track changes, use branches, and share projects on GitHub. Start with the basics and learn the commands developers use every day.

Backbencher Administrator2026-10-28

Git & GitHub Notes — Backbencher Codes

← Back to Backbencher Codes Compiler

These notes cover the basics and advanced Git workflows. Each section includes explanations and terminal examples you can try in your own practice repository.

Table of Contents

  1. Git & GitHub Basics
  2. Install & Configure Git
  3. Repository Basics
  4. The Git Workflow
  5. Core Commands
  6. File States & .gitignore
  7. Push, Pull & Clone
  8. Branching
  9. Merging
  10. Stashing
  11. Collaboration
  12. Raising a Pull Request
  13. Reviewing a Pull Request
  14. Merging a PR & Handling Rejection
  15. Merge Conflicts
  16. Undo Changes
  17. Rebase & Interactive Rebase
  18. Reflog — Recovering Lost Work
  19. Cherry-Picking Commits
  20. Forking & Branch Rulesets
  21. More Power Tools
  22. README & Documentation
  23. Best Practices

Topic 1: Git & GitHub Basics {#topic-1}

What they are, why they exist, and how they're different

Say you're building a personal portfolio site. Every day you tweak the CSS, add a new section, maybe break something by accident. If you're not careful, you end up with a folder like this:

portfolio-final
↓
portfolio-final-v2
↓
portfolio-final-REAL-final
↓
nobody knows which one actually works 😵

Key Concept

Git is a tool that saves the history of every change you make to your project, so you never need duplicate folders again. GitHub is a website that stores a backup of that history online, so you can share it and work with other people.

Think of Git like the "Version History" feature in Google Docs — every edit is remembered, and you can jump back to any earlier version instantly. GitHub is like uploading that document to Google Drive so your teammates can open it too.

Git vs GitHub — the classic interview question

What Git GitHub
What is it? A tool installed on your computer A website that hosts Git projects online
Needs internet? No — works fully offline Yes — it lives on the web
Made by Linus Torvalds (2005) Owned by Microsoft
Cost Free & open source Free plan + paid plans

Easy way to remember it: Git = Camera (takes the snapshot). GitHub = Google Photos (stores it online so others can see it).

Why does this matter for a web developer?

Imagine three of you are building a React app together — one person builds the navbar, another the login page, another the footer. Without Git, you'd be emailing zip files back and forth and constantly overwriting each other's work. Git lets everyone edit the same project safely, and GitHub gives you one shared "source of truth" online.


Topic 2: Install & Configure Git {#topic-2}

Getting your machine ready before your first commit

Before Git can track anything, it needs two things installed and one thing configured: your identity (name + email). Every change you save gets stamped with "who did this."

Step 1 — Install

Download Git from git-scm.com for Windows, or use your terminal on Mac/Linux:

Example (macOS):

brew install git

Example (Ubuntu / Debian):

sudo apt install git

Step 2 — Verify

Example (Terminal):

git --version
# git version 2.51.0 — you're good to go

Step 3 — Configure your identity

Example (Terminal):

git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Flag Value Used What it does
--global — Applies this name/email to every project on your computer, not just one.
user.name "Your Name" Shows up as the author on every commit you make.
user.email you@email.com Use the same one as your GitHub account so commits link back to your profile.

If your Git email doesn't match your GitHub email, your commits won't show up on your GitHub contribution graph — a common beginner surprise.

Check what's configured anytime with git config --list, and create a free account at github.com if you haven't already — you'll need it from Section 7 onward.


Topic 3: Repository Basics {#topic-3}

Turning an ordinary folder into a Git project

A repository (or "repo") is just a project folder that Git is watching. Say you have a folder for a to-do list app:

todo-app
├── index.html
├── style.css
└── script.js

Right now, Git knows nothing about it. To start tracking it:

Example (Terminal):

cd todo-app
git init
# Initialized empty Git repository

This creates a hidden .git folder inside your project. That's where Git quietly stores every commit, branch, and bit of history — your actual files (index.html, etc.) never move or change.

Key Concept

.git is Git's brain for this project. Deleting it doesn't delete your code — it just makes Git forget every version you ever saved. Never edit its contents by hand.

Run git init only once per project — right when you start it, or right when you decide to start tracking it.


Topic 4: The Git Workflow {#topic-4}

The four stages every change passes through

Every file you touch moves through four areas before it's safely part of your project's history:

  • Working Directory: Your actual project folder — where you edit index.html, add a new component, etc.
  • Staging Area: A waiting room. You pick exactly which changed files you want saved next.
  • Local Repository: A "commit" locks in a permanent snapshot — saved on your computer.
  • Remote Repository (GitHub): A push uploads your commits online so others (and future you) can access them.

Key Concept

Think of the Staging Area like an online shopping cart. Browsing the store = editing files. Adding to cart = git add. Checkout = git commit. Nothing is "bought" (saved forever) until you check out.

Example: building a navbar over one day

9 AM — write navbar HTML
↓
git add . → git commit -m "Add navbar markup"
↓
2 PM — style the navbar with CSS
↓
git add . → git commit -m "Style navbar"
↓
6 PM — push everything to GitHub
↓
git push ✅

Commits happen completely offline — you don't need internet until you're ready to push. So you can commit freely on a flight, a train, or with bad Wi-Fi.


Topic 5: Core Commands {#topic-5}

The six commands you'll type every single day

Flag Value Used What it does
git init — Starts tracking the current folder as a Git repo.
git status — Shows what's changed, staged, or untracked right now.
git add file / . Moves changes into the Staging Area.
git commit -m "message" Saves a permanent snapshot with a message describing it.
git log --oneline — Shows your commit history, one line per commit.
git diff — Shows exactly what lines changed, before you commit.

A real example: fixing the background color

Example (Terminal):

git status
# modified: style.css

git diff
- background: white;
+ background: #111827;

git add style.css
git commit -m "Switch hero section to dark background"

Good commit message: "Fix mobile navbar overlap". Bad commit message: "update" or "final". Describe what changed, not that something changed.


Topic 6: File States & .gitignore {#topic-6}

Untracked, modified, staged — and what Git should never touch

  • Untracked: A brand new file Git has never seen, e.g. a new about.html you just created.
  • Modified: Git already knows this file, but you've changed it since the last commit.
  • Staged → Committed: You've run git add, then git commit — the change is now locked in.

.gitignore — telling Git what to skip

In a React or Node project, some folders/files should never be uploaded to GitHub — like your node_modules folder (can be 100,000+ files!) or your .env file (which holds secret API keys).

Example (.gitignore):

node_modules/
.env
dist/
build/
*.log

Never commit a .env file. It usually contains database passwords, API keys, or secret tokens — leaking these on a public GitHub repo is a real security risk.

Create your .gitignore before your first commit. Once Git is already tracking a file, adding it to .gitignore later won't make Git stop watching it automatically.


Topic 7: Push, Pull & Clone {#topic-7}

Connecting your local project to GitHub

So far, all your commits live only on your laptop. To back them up (and let others see them), connect your project to a GitHub repository.

Step 1 — Connect

Example (Terminal):

git remote add origin https://github.com/you/todo-app.git

origin is just a nickname for "the GitHub URL I'm connected to."

Step 2 — Push (first time)

Example (Terminal):

git push -u origin main

After this, every future push is as simple as git push — Git remembers where to send it.

Cloning someone else's project

Example (Terminal):

git clone https://github.com/friend/react-blog.git

This downloads the entire project — files, branches, and full commit history — as if you'd been there from day one.

Pull vs Fetch

What git fetch git pull
Downloads new changes? Yes Yes
Updates your files immediately? No — you review first Yes — merges right away

Think WhatsApp: fetch is seeing "5 new messages" without opening them. pull is opening and reading them — your view updates instantly.


Topic 8: Branching {#topic-8}

Working on new features without breaking what already works

Say your React app is live and working. Now you want to add a dark mode toggle — but what if it breaks the whole app? You don't experiment directly on main. Instead, you create a branch: an independent copy of your project where you can safely try things.

Example (Terminal):

git switch -c dark-mode
# creates AND switches to the new branch in one step
Flag Value Used What it does
git branch — Lists all branches; the current one has a *.
git switch name Moves you into an existing branch.
git switch -c name Creates a new branch and jumps into it immediately.
git branch -d name Deletes a branch once its work is merged in.

Key Concept

Changes made on dark-mode stay invisible on main until you merge them. Switch back to main and your dark mode code simply isn't there — safely tucked away in its own branch.

Good branch names

feature/dark-mode
·
bugfix/navbar-overlap
·
docs/readme-update
test
·
temp
·
abc
← avoid these

Topic 9: Merging {#topic-9}

Bringing a finished feature branch back into main

Once dark mode works perfectly on its own branch, it's time to combine it back into main.

Example (Terminal):

git switch main
git merge dark-mode

Always switch to the branch you want to merge into first (usually main), then run merge with the feature branch's name.

Fast-forward vs Three-way merge

What Fast-forward Three-way
When it happens main hasn't changed since you branched Both branches got new commits
Extra "merge commit"? No — pointer just moves forward Yes — Git creates one to combine histories

After merging, delete the now-unneeded branch:

Example (Terminal):

git branch -d dark-mode

Don't worry — your dark mode code stays in main's history. Only the branch label disappears.


Topic 10: Stashing {#topic-10}

Temporarily setting aside unfinished work

Imagine you're halfway through building a search bar on the feature/search branch — messy, half-working code — when your teammate says "quick, switch to main, there's a bug in production!" You can't commit unfinished, broken code. That's exactly what stashing is for.

Key Concept

git stash takes your uncommitted changes and tucks them away in a hidden "shelf," giving you back a clean working directory — without creating a commit.

Step 1 — Save your unfinished work

Example (Terminal):

git stash
# Saved working directory state WIP on feature/search: ...

Step 2 — Do the urgent fix

Example (Terminal):

git switch main
# fix the bug, commit, push...

Step 3 — Bring your work back

Example (Terminal):

git switch feature/search
git stash pop
Flag Value Used What it does
git stash — Shelves your current uncommitted changes.
git stash list — Shows every stash you've saved, most recent first.
git stash pop — Restores the most recent stash and removes it from the shelf.
git stash apply — Restores the stash but keeps a copy on the shelf too.
git stash drop — Deletes a stash you no longer need.
git stash save "message" Same as stash, but with a note so you remember what it was.

Pop vs Apply: pop = "take it off the shelf and use it" (removes it from the stash list). apply = "make a copy from the shelf but leave the original there too" — handy if you want to apply the same stash to two different branches.

Stashes aren't tied to a specific branch — you can stash on one branch and pop it on another. This is powerful, but can also cause confusing conflicts if you're not paying attention to which branch you're on.


Topic 11: Collaboration {#topic-11}

How multiple developers safely share one project

Say four of you are building an e-commerce site: one on login, one on the cart, one on payments, one on the admin dashboard. GitHub gives you two main ways to work together.

What Collaborator Access Fork & PR
Used for Company / team projects Open-source contributions
How it works Owner invites you directly to the repo You copy the repo to your own account, then propose changes back

Key Concept

A fork is your own personal copy of someone else's repository. You can experiment freely there — the original project stays untouched until you formally ask them to include your changes.

The golden rule of team collaboration: never build features directly on main. Each feature gets its own branch, keeping everyone's work isolated until it's reviewed and ready.


Topic 12: Raising a Pull Request {#topic-12}

Asking the team to review your work before it joins the main project

You've finished the login feature on your feature/login branch. Should you merge it into main yourself? No. Professional teams never let developers merge directly into important branches. Instead, they open a Pull Request (PR) — a formal request that says: "I've finished my work, please review it before it becomes part of the main project."

Key Concept

Think of it like a group assignment. You finish your section, but instead of inserting it straight into the final document, you send it to your teacher first. They review it, suggest corrections, approve it — and only then does it get added. A Pull Request works exactly the same way.

Why do we even need Pull Requests?

Imagine 20 developers on one team. If everyone pushed directly into main, bugs would pile up fast, code quality would drop, and a single mistake could break the live site. PRs fix this by forcing every change through code review, discussion, testing, and approval before it's safely merged.

The full Pull Request workflow

  • Create branch: git switch -c feature/login
  • Develop the feature & commit: Build login, commit in small logical chunks.
  • Push the branch: git push origin feature/login
  • Create Pull Request: login-feature → main, with title + description.
  • Code review: A teammate reads, tests, and comments on it.
  • Approve → Merge → Delete branch: Once approved, it's merged into main and the feature branch is cleaned up.

This exact cycle is what almost every software company — from small startups to Google and Netflix — runs, every single day.

Step-by-step: creating your PR

Step 1 — Push your branch to GitHub

Example (Terminal):

git push origin feature/login

Step 2 — Open GitHub

GitHub will usually display a banner that says "Compare & pull request" right after your push. Click it.

Step 3 — Fill in the details, then submit

Fill in a Title and a Description, then click "Create Pull Request." Done — your PR is now waiting for review.

Writing a good PR title

A good title clearly describes the feature — not just that "something" changed. Many teams also prefix the title with the type of change, similar to commit message conventions, so reviewers know what they're looking at before opening it.

✓ Add User Authentication
✓ Fix Navbar Alignment
✓ Implement Dark Mode
✓ Create Payment API
✗ Update
·
✗ Changes
·
✗ Final
·
✗ Done
Flag Value Used What it does
feat: feat: add user authentication A new feature is being introduced.
fix: fix: navbar overlap on mobile A bug fix, nothing new added.
refactor: refactor: simplify auth middleware Code restructured, behavior unchanged.
docs: docs: update setup instructions Documentation-only changes.
chore: chore: bump dependencies Maintenance work — no feature or fix.

Writing a good PR description

A solid description answers: what changed, why it changed, and how you tested it (screenshots help too). Rather than one paragraph, most teams use a structured, sectioned template — this keeps every PR consistent and makes reviewers' jobs much faster, since they know exactly where to look for each piece of information.

Key Concept

Reviewers are busy. A templated description lets them scan straight to "Related Issue" or "Testing" instead of hunting through a wall of text. Many teams save this exact template as a .github/PULL_REQUEST_TEMPLATE.md file, so GitHub auto-fills it into every new PR's description box.

Example (PR Description Template):

## Description
Briefly describe what this PR changes.

## Changes Made
- Added ...
- Fixed ...
- Updated ...

## Why
Explain why these changes are needed.

## Testing
- Tested locally
- No errors found

## Screenshots
(Add if applicable)

## Related Issue
Closes #123

## Checklist
- [x] Code follows project guidelines
- [x] Tested locally
- [x] Documentation updated (if needed)
- [x] Ready for review

What each section is for

Flag Value Used What it does
## Description 1–2 sentences A quick summary a reviewer can read in five seconds to know what this PR is about.
## Changes Made bullet list The concrete list of what was added, fixed, or updated — the "diff" in plain English.
## Why short paragraph The reasoning or motivation — the bug it solves, the feature it enables, or the issue it addresses.
## Testing bullet list How you verified it works — manual testing, automated tests run, edge cases checked.
## Screenshots image / gif Visual proof for UI changes — drag-and-drop an image straight into GitHub's PR description box.
## Related Issue Closes #123 Links back to the tracked issue — GitHub auto-closes it when this PR merges.
## Checklist - [x] item Self-review checkboxes confirming the PR is actually ready, not still a work in progress.

In ## Related Issue, keywords like Closes, Fixes, or Resolves followed by an issue number (e.g. Closes #123) aren't just for readability — GitHub detects them and automatically closes that issue the moment this PR is merged.

Before you open a PR — checklist

  • Does the project build successfully?
  • Did I test my code myself first?
  • Are my commit messages meaningful?
  • Is my branch up to date with main?
  • Did I remove unnecessary/leftover code (console.logs, commented-out blocks)?

If your feature isn't finished yet but you want early feedback, open a Draft Pull Request instead. It clearly tells reviewers "still in progress, please don't merge yet."

Two common mistakes when raising a PR: opening it from the wrong source/target branch (always double-check which branch merges into which), and submitting a huge PR with hundreds of unrelated file changes — keep each PR focused on one feature.


Topic 13: Reviewing a Pull Request {#topic-13}

How teams check code quality before it ships

Now flip roles — you're the reviewer, checking a teammate's feature/cart PR before it becomes part of the shared codebase. One of the biggest advantages of Pull Requests is Code Review: another developer checks your code before it's merged. Even experienced developers make mistakes — a second pair of eyes regularly catches bugs, typos, security issues, and performance problems that the original author missed.

What happens after a PR is created?

  • Reviewer reads the code: Goes through every changed file in the "Files changed" tab.
  • Reviewer tests the feature: Pulls the branch locally or checks CI results to confirm it actually works.
  • Reviewer gives feedback: Leaves inline comments directly on the relevant lines of code.
  • Developer updates the code: Commits fixes and pushes to the same branch.
  • Reviewer approves → Merge: Once satisfied, the reviewer approves and the PR is merged.

What a good reviewer checks

Flag Value Used What it does Why it matters
Code Quality clean, simple logic Is the implementation as simple as it can reasonably be? Simpler code has fewer places for bugs to hide.
Readability clear names Can the next developer understand this in 6 months? Code is read far more often than it's written.
Performance no unnecessary work Are there obvious slowdowns — e.g. loops inside loops, unneeded re-renders? Keeps the app fast as it grows.
Bugs / Logic edge cases Does it handle an empty cart, a failed API call, invalid input? Prevents issues from reaching production.
Security no secrets/leaks No hard-coded API keys, no unsafe handling of user input. One leaked key can compromise the whole app.
Best Practices matches team style Follows the project's existing conventions and patterns. Keeps the codebase maintainable long-term.

The three review outcomes

  1. Approve

Everything looks good. The reviewer clicks Approve — the PR is now ready to merge.

  1. Request Changes

The reviewer found real issues that must be fixed before merging. For example: "Improve variable names," "Fix responsive layout," "Add error handling." The developer updates the branch, and the Pull Request updates automatically.

  1. Comment

The reviewer is simply asking questions or suggesting ideas, without blocking the merge — for example: "Why did you choose this approach?" or "Can we simplify this function?"

Updating a Pull Request after feedback

Key Concept

A common beginner misconception: "I have to create a new Pull Request after every change." Wrong. Simply make changes, commit, and push to the same branch — the existing PR updates automatically.

Example (Terminal — author fixing review comments):

git add .
git commit -m "Fix review comments"
git push

Approving and merging

When everything looks good, the reviewer clicks Approve. Then, to actually combine the code, someone clicks "Merge Pull Request" — GitHub combines the feature branch into the target branch (usually feature/cart → main).

What Merge Close
Result Code becomes part of the project Code is rejected or postponed — no code is merged
Branch Usually deleted after merging May still exist for later use

Every PR also keeps a full conversation — comments, suggestions, reviews, commit history, and changed files — so the whole discussion around a feature lives in one place.

Good review culture: be specific and kind. Instead of "this is wrong," try "This might break if items is undefined — could we add a default value?" Never approve code blindly — and always address review comments before requesting another look.


Topic 14: Merging a PR & Handling Rejection {#topic-14}

How teams finish the review cycle — and what to do if your PR gets turned down

Merging, at industry level

Once a PR is approved (often requiring 1–2 approvals, plus passing automated tests/CI), it's ready to merge. GitHub usually offers three merge styles:

Flag Value Used What it does Why it matters
Merge commit keeps all commits Adds every commit from the branch, plus one merge commit. Full history preserved, but can get noisy.
Squash & merge one clean commit Combines all the branch's commits into a single commit on main. Keeps main's history clean — most companies default to this.
Rebase & merge linear history Replays your commits on top of main, one by one, no merge commit. Very clean history, used by teams wanting a straight-line log.

Most companies use Squash & Merge by default for feature branches — it keeps main's history readable: one commit per feature, instead of "wip", "fix typo", "oops" scattered everywhere.

After merging, the standard next step:

Example (Terminal):

git switch main
git pull
git branch -d feature/login

What if your PR gets rejected?

It happens to everyone — even senior engineers. A "rejected" PR usually means one of two things: the reviewer requested changes, or the PR was closed without merging altogether (maybe the feature isn't needed anymore, or the approach needs rethinking).

Step 1 — Don't take it personally

Code review feedback is about the code, not you. Every experienced developer has had PRs sent back for changes — it's a normal, healthy part of shipping good software.

Step 2 — Read the feedback carefully

Understand why it was rejected. If it's unclear, it's completely fine to ask: "Could you clarify what you mean by this comment?"

Step 3 — Fix and push again

Example (Terminal):

git switch feature/login
# make the requested changes
git add .
git commit -m "Address review feedback: validate email format"
git push

Then re-request a review on GitHub instead of opening a brand new PR — this keeps the whole discussion in one place.

If the whole PR was closed (not just changes requested)

Talk to your team about the reasoning first. Sometimes the feature direction changed, or a different approach is preferred. If you still want to pursue it, you can branch off the latest main and rebuild with the new feedback in mind:

Example (Terminal):

git switch main
git pull
git switch -c feature/login-v2

Avoid force-pushing over a reviewer's comments or arguing in the PR thread. If you disagree with feedback, discuss it calmly, or loop in a lead/senior developer to help decide the right approach.

Key Concept

A rejected or "changes requested" PR isn't the end of your work — it's the review process doing its job. The goal is always a better main branch, not a perfect first attempt.


Topic 15: Merge Conflicts {#topic-15}

What to do when Git can't decide for you

Say you changed the header's background to black, and your teammate changed the very same line to blue — on a different branch. When merging, Git has no idea which one you actually want. That's a merge conflict.

Example (style.css — conflict markers):

<<<<<<< HEAD
background: black;
=======
background: blue;
>>>>>>> feature/header

Edit the file, delete the markers, and keep whichever version (or combination) you actually want:

Example (Terminal):

git add style.css
git commit

Conflicts are completely normal — even experienced developers hit them regularly. They just mean two people touched the same line; Git needs a human to pick the final answer.


Topic 16: Undo Changes {#topic-16}

Because mistakes should never be permanent

Flag Value Used What it does
git restore file Discards uncommitted changes, back to the last commit. Very safe.
git reset --soft HEAD~1 Undoes the last commit but keeps your changes staged (great for fixing a bad commit message).
git reset --hard HEAD~1 Deletes the last commit AND all its changes completely. Use with caution.
git revert HEAD Creates a new commit that undoes an earlier one — safe for shared branches.

Never use git reset --hard on a branch others have already pulled — it rewrites history. On shared branches, always prefer git revert, which preserves history instead of erasing it.


Topic 17: Rebase & Interactive Rebase {#topic-17}

Rewriting history to keep it clean and linear

Rebase takes the commits from your branch and replays them one-by-one on top of another branch, instead of creating a merge commit that ties the two histories together. The end result looks as if you'd branched off much later — a straight line, not a web of merges.

Key Concept

Merge preserves exactly what happened (including the "join point"). Rebase rewrites what happened, so it looks like your work started from the latest code. Neither is "wrong" — they trade off honesty of history against readability of history.

Rebase vs merge, visually

git merge
feature into main
main:    A---B---C-------
M
\_____/
feature:    D---E
git rebase
feature onto main
main:    A---B---C
feature:           \---
D'
---
E'
(new commit IDs)

Basic rebase

Example (Terminal):

git checkout feature/navbar
git rebase main # replays feature/navbar's commits on top of latest main

Interactive rebase — editing history itself

git rebase -i opens an editable list of your last commits, letting you reorder, combine, rename, or drop them before they're finalized. It's the tool for turning "wip", "fix typo", "actually fix typo" into one clean commit.

Example (Terminal):

git rebase -i HEAD~3 # open the last 3 commits for editing
Flag Value Used What it does
pick (default) Keep this commit exactly as it is.
reword r Keep the changes, but let you edit the commit message.
squash s Merge this commit into the one above it, combining their messages.
fixup f Like squash, but silently discards this commit's message.
drop d Delete this commit entirely, as if it never happened.
edit e Pause at this commit so you can amend its content, then continue.

After changing a line, save and close the editor. If you marked a commit edit, make your changes and run:

Example (Terminal):

git add .
git rebase --continue

If a rebase hits a conflict

Example (Terminal):

# fix the conflicted file(s), then:
git add <file>
git rebase --continue

# or bail out completely and go back to how things were:
git rebase --abort

The golden rule of rebasing: never rebase commits that have already been pushed and that other people have pulled. Rebase rewrites commit hashes — if teammates already built on the old ones, you'll create a confusing, duplicated history for everyone. Rebase your own local/feature work; merge (or git pull --rebase only on branches solely yours) once it's shared.


Topic 18: Reflog — Recovering Lost Work {#topic-18}

Git's private safety net that almost nothing can defeat

Every time HEAD moves — a commit, a checkout, a reset, a rebase, even an aborted merge — Git quietly logs it in the reference log (reflog). It's local-only (never pushed, never shared) and it's the reason "I accidentally deleted my commit" is almost never fatal.

Key Concept

A "deleted" commit is rarely actually gone — Git just stops pointing at it. As long as it's still in the reflog (default ~90 days for reachable commits, ~30 days for unreachable ones), you can point something back at it and get your work back.

Example (Terminal):

git reflog

# example output:
a1b2c3d HEAD@{0}: rebase (finish): returning to refs/heads/main
e4f5g6h HEAD@{1}: commit: Add payment validation
i7j8k9l HEAD@{2}: reset: moving to HEAD~1
m0n1o2p HEAD@{3}: commit: Fix login bug

Recovering a "lost" commit

Say a git reset --hard just wiped out a commit you actually needed. Find it in the reflog, then reset back onto it:

Example (Terminal):

git reflog # find the entry right before the mistake, e.g. HEAD@{2}
git reset --hard HEAD@{2}

# or, if you'd rather not touch your current branch:
git checkout -b recovered-work HEAD@{2}

Reflog is your panic button for rebases-gone-wrong, accidental hard resets, deleted branches, and detached-HEAD confusion. Whenever something feels like it "disappeared," check git reflog before assuming it's actually lost.

Reflog is local to your machine only — it isn't pushed to GitHub and won't help recover a teammate's history, and it does eventually expire and get garbage-collected. It's a safety net, not permanent storage.


Topic 19: Cherry-Picking Commits {#topic-19}

Grabbing one specific commit without merging everything else

git cherry-pick copies the changes from one specific commit on another branch and applies them as a new commit on your current branch — without pulling in anything else that branch has. Useful for backporting a hotfix, or grabbing just one teammate's commit out of a much bigger feature branch.

Example (Terminal):

git checkout main
git cherry-pick a1b2c3d # applies just this one commit onto main
Flag Value Used What it does
git cherry-pick Applies that single commit's changes as a new commit here.
git cherry-pick A..B Applies a whole range of commits (exclusive of A), in order.
git cherry-pick --no-commit Applies the changes to your working directory, but doesn't commit — lets you review or combine first.
git cherry-pick --continue Resumes after you've resolved a conflict from a cherry-pick.
git cherry-pick --abort Cancels the cherry-pick and returns to how things were before.

Because cherry-pick replays a commit's changes elsewhere, it can hit merge conflicts just like a merge or rebase can — resolve the file, git add it, then continue:

Example (Terminal):

git add <file>
git cherry-pick --continue

Cherry-picked commits get a brand-new commit hash on the destination branch, even though the change is identical — Git treats it as its own, separate commit.


Topic 20: Forking & Branch Rulesets {#topic-20}

Contributing to repos you don't own, and protecting the ones you do

The full fork workflow

A fork is your own personal copy of someone else's repository, sitting on your own GitHub account. It's how you contribute to projects you don't have write access to — like most open-source repositories.

  • Fork: Click "Fork" on GitHub — creates yourname/project, a full copy under your account.
  • Clone your fork: git clone your fork down to your machine.
  • Branch, commit, push: Do your work on a feature branch, then push it to your fork.
  • Open a PR: Open a Pull Request from your fork's branch into the original project's main .
  • Keep your fork in sync: The original project keeps moving — regularly pull its changes into your fork.

Keeping a fork up to date with the original ("upstream")

Example (Terminal):

git remote add upstream https://github.com/original-owner/project.git
git fetch upstream
git checkout main
git merge upstream/main # or: git rebase upstream/main
git push origin main # origin = your fork

Key Concept

origin is a nickname for your fork (where you push); upstream is a nickname you add yourself for the original repo (where you pull updates from). This is what lets you stay current without ever needing write access to the source project.

Branch protection rules & Rulesets

On repos you do control, GitHub lets you stop force-pushes, accidental deletions, and unreviewed merges straight into important branches. This started as Branch Protection Rules and has since been extended by Rulesets — a newer, more flexible layer that can also target tags and apply across multiple branches at once by pattern.

What Branch Protection Rules Rulesets
Scope One exact branch name or pattern Multiple branches/tags, combinable, with include/exclude patterns
Layering One rule set applies at a time Multiple rulesets can stack on the same branch
Visibility Only visible to admins Can be marked visible to all contributors, so people see why a push was blocked
Where it lives Settings → Branches Settings → Rules → Rulesets

Common rules teams turn on

  • Require a pull request before merging — nobody pushes straight to main, not even admins.
  • Require approvals — e.g. at least 1–2 reviewers must approve before a PR can merge.
  • Require status checks to pass — CI tests, linters, or build pipelines must succeed first.
  • Require conversation resolution — every review comment thread must be marked resolved.
  • Block force pushes — stops anyone from rewriting the shared branch's history.
  • Restrict deletions — the branch can't be deleted, even by mistake.
  • Require signed commits — every commit must be cryptographically signed to prove who really authored it.

Protecting main is one of the highest-value, lowest-effort things a team can set up on day one — it turns "please don't push directly to main" from a polite request into something GitHub actually enforces.


Topic 21: More Power Tools {#topic-21}

Lesser-known commands that pay off once projects get bigger

git bisect — binary-searching for the commit that broke things

When something used to work and now doesn't, but you don't know which of 50 commits caused it, bisect does a binary search through history for you, halving the search space each time.

Example (Terminal):

git bisect start
git bisect bad # current commit is broken
git bisect good v1.2.0 # this old tag was fine
# Git checks out a commit halfway between — test it, then say:
git bisect good # or: git bisect bad
# repeat until Git names the exact first-bad commit
git bisect reset # done — return to where you started

git tag — marking release points

Example (Terminal):

git tag v1.0.0 # lightweight tag — just a name on a commit
git tag -a v1.0.0 -m "First stable release" # annotated — stores author, date, message
git push origin v1.0.0 # tags aren't pushed automatically

git worktree — multiple branches checked out at once

Normally you can only have one branch checked out per repo folder. worktree gives you a second working directory linked to the same repo, so you can have two branches open side-by-side without stashing or cloning twice.

Example (Terminal):

git worktree add ../hotfix-dir hotfix/urgent-bug

git submodule — a repo inside a repo

Lets one Git repository include another repository as a subdirectory, pinned to a specific commit — common for shared libraries kept in their own repo.

Example (Terminal):

git submodule add https://github.com/org/shared-ui.git libs/shared-ui
git clone --recurse-submodules https://github.com/org/project.git # clone with submodules included

Git hooks — automation on every commit or push

Hooks are scripts stored in .git/hooks/ that Git runs automatically at points like pre-commit or pre-push — commonly used to run linters or tests before a commit is allowed through.

Flag Value Used What it does
git bisect good / bad Binary-searches commit history to find exactly where a bug was introduced.
git tag -a v1.0.0 Marks a specific commit as a named release point.
git worktree add Checks out another branch into a separate folder at the same time.
git submodule add Nests another Git repo inside this one, pinned to a commit.
git blame file Shows who last changed each line of a file, and in which commit.
git log --graph --oneline --all Draws a compact ASCII graph of all branches and how they connect.

You won't need most of these day-to-day — but knowing they exist means that when a specific hard problem shows up (which commit broke this? which branch touches this bug? I need two branches open at once), you'll recognize the right tool instead of reaching for a workaround.


Topic 22: README & Documentation {#topic-22}

The first thing anyone sees when they open your repo

A recruiter opens your GitHub repo. If all they see is index.html, style.css, script.js with no explanation, they'll likely close the tab in 10 seconds. A good README.md changes that completely — it's usually the first file people read, and GitHub automatically displays it on your repository's homepage.

Key Concept

Historically, developers named this file README to literally tell people "read me first." Today the standard filename is README.md — the .md extension stands for Markdown, a simple text format GitHub automatically turns into nicely styled documentation.

Think of it like buying a new washing machine — the manual inside the box explains setup, features, usage, and troubleshooting. Your README is that manual, but for your project.

How to add a README to your repo

Step 1 — Create the file

Example (Terminal):

touch README.md

Place it in the root of your project folder — the same level as package.json or index.html.

Step 2 — Write your content using Markdown

Fill it in using the Markdown syntax below (see the reference table), then save it.

Step 3 — Commit and push it like any other file

Example (Terminal):

git add README.md
git commit -m "Add project README"
git push

GitHub will now automatically render it on your repository's homepage — no extra setup needed.

Basic Markdown syntax reference

Flag Value Used What it does
Headings # ## ### One # for the biggest heading, more #s for smaller ones — e.g. # Heading 1, ## Heading 2.
Bold **text** Renders as text.
Italic *text* Renders as text.
Bold + Italic ***text*** Renders bold and italic together.
Bullet List - item One dash per line creates an unordered list.
Numbered List 1. item Numbers followed by a period create an ordered list.
Code Block ```javascript Triple backticks (optionally with a language name) create a formatted code block.
Inline Code git clone Single backticks highlight a short code snippet inline with text.
Link text Creates a clickable hyperlink.
Image alt Displays an image inline — same as a link, with a ! in front.
Horizontal Line --- Three dashes on their own line create a divider between sections.

Example (Markdown syntax examples):

# Heading 1
## Heading 2

**GitHub**        # bold
*Git*             # italic
***Git***         # bold + italic

- HTML
- CSS
- JavaScript

1. Install
2. Run
3. Enjoy

`git clone`       # inline code
[GitHub](https://github.com)
![Portfolio](image.png)

---

Structure of a professional README

Project Title
↓
Description
↓
Features
↓
Tech Stack
↓
Installation
↓
Usage
↓
Folder Structure
↓
Screenshots / Live Demo
↓
Author & License

A complete example

Example (README.md):

# Portfolio Website

A personal portfolio website built using HTML, CSS and JavaScript.

## Features
- Responsive Design
- Dark Mode
- Smooth Animations

## Tech Stack
- HTML
- CSS
- JavaScript

## Installation
git clone https://github.com/you/portfolio.git

## Author
Your Name

Simple, clean, professional — and exactly the kind of thing a recruiter (or teammate) can understand in ten seconds.

README vs Wiki vs Documentation

What README Wiki / Docs
Length One file, quick overview Multiple pages, in-depth
Where it lives Repository homepage Separate documentation section
Best for First impressions, setup steps API references, deployment guides, FAQs

A good README should always include: project name, description, features, tech stack, installation steps, usage instructions, and author info. Screenshots, a live demo link, and a license are optional but make a strong extra impression.

Avoid a one-line README like "My Project" — it tells readers nothing. And remember to update it whenever the project changes significantly; an outdated README can be more confusing than none at all.


Topic 23: Best Practices {#topic-23}

The habits that separate professional Git usage from chaos

  • Write commit messages that describe what changed — "Fix mobile navbar overlap", not "update".
  • Keep main stable — always build features on a separate branch.
  • git pull before you start working, to avoid unnecessary conflicts.
  • Keep Pull Requests small and focused — one feature at a time.
  • Never commit .env, API keys, or passwords.
  • Delete branches once they've been merged in.
  • Keep your README.md up to date as the project grows.

Key Concept

Git rewards small, frequent, well-described commits and branches. The habits in this section are exactly what separates a messy solo project from a codebase a whole team can work in together.


About Backbencher Codes

Backbencher Codes shares coding notes and tools to help learners practise programming and understand development topics.

Open the Backbencher Codes Compiler

Tags:ProgrammingWebgitgithubnotesonline compiler

Want to test code live?

Open our VS Code-like online compiler with 14 languages supported right in your browser.

Launch Online IDE →