⚡ Phase 3 · Advanced & CI/CD 🔴 Advanced MODULE 07

Advanced Git

⏱️ 55 min
💻 Hands-on
🧩 5 Quiz Questions
🏗️ 1 Challenge
Course progress87%
🎯 What you'll learn: Git stash for saving work in progress. Interactive rebase to clean up commit history before a PR. Cherry-pick to apply specific commits. The three reset modes and when each is safe. Git reflog — your safety net for recovering anything. Annotated tags for releases. Git aliases to speed up your workflow.

Git Stash — Save Work in Progress

You're deep in a feature when a critical bug report comes in — you need to switch branches immediately, but your work isn't ready to commit. git stash is your escape hatch: it shelves your changes so you can switch contexts and come back later.

git stash — full command reference
BASH
# Stash current uncommitted changes (tracked files)
git stash

# Stash with a descriptive message (highly recommended)
git stash save "WIP: feature X — halfway through the auth logic"

# Also stash untracked (new) files
git stash -u

# List all stashes
git stash list
# stash@{0}: WIP: feature X — halfway through the auth logic
# stash@{1}: WIP on main: abc1234 fix: navbar color

# Apply most recent stash (keeps it in the list)
git stash apply

# Apply AND remove from list (most common)
git stash pop

# Apply a specific stash by index
git stash apply stash@{2}

# Delete a specific stash
git stash drop stash@{0}

# Delete ALL stashes
git stash clear

Interactive Rebase — Rewrite History

Interactive rebase lets you rewrite your commit history before pushing. This is how professionals keep their PRs clean: squash messy "WIP" commits into meaningful ones, fix typos in commit messages, and reorder commits for logical clarity.

⚠️
Golden rule of rebase: never rewrite shared history
Only use interactive rebase on commits that haven't been pushed to a shared branch yet (or on your own feature branch). Rewriting commits that others have based work on creates chaos. If you've already pushed, use --force-with-lease carefully.
Interactive rebase — squashing commits
BASH
# Rebase the last 3 commits interactively
git rebase -i HEAD~3
# This opens your configured editor with something like:
#
# pick a1b2c3d feat: add user model
# pick d4e5f6g WIP: testing stuff
# pick h7i8j9k fix: forgot to save
#
# Change 'pick' to:
#   squash (s) — merge into previous commit, combine messages
#   fixup  (f) — merge into previous commit, discard this message
#   reword (r) — keep commit but edit the message
#   drop   (d) — completely remove this commit
#
# Example: squash all 3 into one
# pick a1b2c3d feat: add user model
# fixup d4e5f6g WIP: testing stuff
# fixup h7i8j9k fix: forgot to save
#
# Save and close editor. Git will combine the commits.
# You'll be prompted to write the final commit message.
💡
squash vs fixup
squash keeps the squashed commit's message and prompts you to combine them — great when both messages have useful info. fixup discards the squashed commit's message entirely and just uses the top commit's message — perfect for "fix typo", "WIP", and "oops" commits.

Cherry-Pick — Apply Specific Commits

git cherry-pick copies a specific commit from anywhere in history and applies it to your current branch. It's like saying "I want exactly this change, and nothing else from that branch."

git cherry-pick examples
BASH
# Apply a single commit to current branch
git cherry-pick a3f5b2c

# Apply multiple commits
git cherry-pick a3f5b2c d7e9f1a

# Apply a range of commits (from..to, exclusive of first)
git cherry-pick a3f5b2c..d7e9f1a

# Cherry-pick without committing (stage only)
git cherry-pick -n a3f5b2c

# If a conflict arises during cherry-pick:
# 1. Resolve the conflict in your editor
# 2. Stage the resolved file
git add conflicted-file.js
# 3. Continue
git cherry-pick --continue
# Or abort entirely:
git cherry-pick --abort

Common cherry-pick scenarios: A critical bug was fixed in a feature branch, but main needs it now without the unfinished feature. A hotfix needs to go to both main and a release/v2 branch. You accidentally committed to the wrong branch and want to move just that commit.

Resetting Commits — Three Modes

git reset moves HEAD (and the branch pointer) backwards in history. The three modes control what happens to your working directory and staging area after the reset. Choosing the wrong mode can mean lost work.

Mode Commits Staging Area Working Directory Safety
--soft Moved Unchanged (staged) Unchanged ✅ Safe
--mixed (default) Moved Cleared (unstaged) Unchanged ⚡ Careful
--hard Moved Cleared Cleared (lost!) ❌ Destructive
git reset — practical examples
BASH
# --soft: Undo last commit, keep changes staged
# Use when: you want to recommit with a better message or add more files
git reset --soft HEAD~1

# --mixed: Undo last commit, keep files but unstage them
# Use when: you want to review/edit before re-staging
git reset HEAD~1
# (same as --mixed which is the default)

# --hard: Undo last commit AND discard all changes
# Use when: you want to completely throw away the last commit
git reset --hard HEAD~1

# --hard to a specific commit hash
git reset --hard a3f5b2c

# Undo last 3 commits, keep code in working dir
git reset --soft HEAD~3
🔥
--hard deletes your work permanently
git reset --hard discards all uncommitted changes with no trash bin, no undo. The only way to recover is git reflog (covered next). Before running any --hard reset, consider using --soft or --mixed first — or at least stash your changes as a safety net.

Git Reflog — Your Safety Net

The reflog (reference log) records every movement of HEAD in your repository — even after resets, rebases, branch deletions, and other "destructive" operations. It's Git's hidden undo history and your safety net when things go wrong.

git reflog — recover anything
BASH
# View the reflog (last 90 days of HEAD movements)
git reflog
# Output example:
# a3f5b2c HEAD@{0}: reset: moving to HEAD~1
# d7e9f1a HEAD@{1}: commit: feat: add login page
# b2c4e6f HEAD@{2}: commit: feat: add user model

# Recover a commit you "lost" with reset --hard
# Find the commit hash in reflog, then:
git checkout d7e9f1a
# You're now in detached HEAD at that commit

# Recover to a new branch from that point
git switch -c recovery/lost-commit

# Or just cherry-pick the recovered commit into your current branch
git cherry-pick d7e9f1a

# Recover a deleted branch
git reflog | grep "feat/deleted-branch"
git switch -c feat/deleted-branch d7e9f1a
🧙
Nothing is truly lost in Git
As long as you haven't run git gc (garbage collection) and less than 90 days have passed, every commit you've ever made is in the reflog. Senior developers call git reflog the "oh no" command — it's saved countless disasters. Accidentally deleted a branch? Lost a rebase? git reflog will find it.

Git Tags — Marking Releases

Tags mark specific points in history as important — typically software releases. Unlike branches, tags don't move when you add commits. They're permanent markers: "this commit is version 1.0.0".

git tag — annotated and lightweight
BASH
# Annotated tag (recommended — stores tagger, date, message)
git tag -a v1.0.0 -m "Release 1.0.0 — initial public release"

# Lightweight tag (just a name pointing to a commit)
git tag v1.0.0-beta

# Tag a specific past commit
git tag -a v0.9.0 a3f5b2c -m "Pre-release v0.9.0"

# List all tags
git tag
git tag -l "v1.*"  # filter pattern

# Show tag details
git show v1.0.0

# Push a specific tag to remote
git push origin v1.0.0

# Push ALL tags to remote
git push origin --tags

# Delete a local tag
git tag -d v1.0.0-beta

# Delete a remote tag
git push origin --delete v1.0.0-beta
📦
Semantic versioning — v MAJOR.MINOR.PATCH
v1.0.0: Major = breaking changes. Minor = new features (backward-compatible). Patch = bug fixes only.
Examples: v2.0.0 = breaking API change. v1.3.0 = new feature added. v1.3.1 = bug fix. Start at v0.1.0 for pre-stable releases.

Git Aliases & Config

Git aliases let you create shortcuts for commands you type constantly. A well-configured .gitconfig file can save hundreds of keystrokes per day. Aliases live in your global config at ~/.gitconfig.

Useful git aliases and config
BASH
# Add aliases via command line
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 --decorate --all"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.unstage "reset HEAD --"

# Or edit ~/.gitconfig directly — [alias] section:
# [alias]
#   st = status
#   co = checkout
#   br = branch -a
#   lg = log --oneline --graph --decorate --all
#   undo = reset --soft HEAD~1
#   save = !git add -A && git commit -m 'SAVEPOINT'
#   wip = !git add -u && git commit -m 'WIP'

# Other useful global settings
git config --global core.editor "code --wait"   # use VS Code
git config --global push.default current              # push to same-name branch
git config --global pull.rebase true                 # rebase on pull
git config --global init.defaultBranch main           # default branch name
🧩 Knowledge Check — Lesson 7
Test your Advanced Git knowledge. 5 questions.
1. What does git stash do?
2. git reset --hard HEAD~1 does what?
3. git cherry-pick a3f5b2c applies:
4. git reflog shows:
5. An annotated tag differs from a lightweight tag because it:
Advanced Challenge — Lesson 7
Interactive rebase and tagging · Advanced
Challenge: Squash & Tag

1. Create a new repo or use an existing one: mkdir adv-git-challenge && cd adv-git-challenge && git init
2. Create commit A: add index.html with git commit -m "feat: add index"
3. Create commit B: edit index.html, git commit -m "WIP: adjusting layout"
4. Create commit C: edit again, git commit -m "fix: typo"
5. Run git log --oneline — you should see all 3 commits
6. Run git rebase -i HEAD~3 — change B and C to fixup in the editor
7. Save and close — B and C squash into A
8. Run git log --oneline — now there's just one clean commit
9. Tag it: git tag -a v0.1.0 -m "Initial release"
10. Verify: git show v0.1.0
💡 Show hints
  • If VS Code is your editor, the rebase file opens as a tab — edit, save, and close that tab
  • Leave the top pick line unchanged — only change the second and third lines to fixup
  • If you get stuck mid-rebase: git rebase --abort to start over
  • git log --oneline --graph gives a nice visual of the history after squashing
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 7 Complete!

Advanced Git unlocked! One more lesson — let's automate everything with GitHub Actions.

Lesson 07 of 09Git & GitHub Mastery