Home

02 Exercise: Understanding Git Pointers and Branches

chapter-02 exercise git branches pointers workflows

Chapter 02 Exercise: Understanding Git Pointers and Branches

Instructions


Question 1: Creating a New Branch

You’re on the main branch and run git checkout -b feature/new-ui. What does the Git graph look like immediately after this command?

Before:
"Add login"  "Fix bug"  "Add dashboard"
     ↓           ↓           ↓
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           main ← HEAD

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           main
                    feature/new-ui ← HEAD

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  m2n3o4p
                              ↑            ↑
                           main    feature/new-ui ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                    feature/new-ui ← HEAD

D)

  a1b2c3d  ←  e4f5g6h
                  ↑
                main

                    i7j8k9l
                        ↑
              feature/new-ui ← HEAD
Show Answer

Correct Answer: A

Creating a new branch with git checkout -b creates a new pointer to the same commit you’re currently on. No new commit is created. Both main and feature/new-ui point to commit i7j8k9l, and HEAD moves to point to the new branch. Option B is wrong because no new commit was made. Option C is wrong because main still exists. Option D is wrong because the branch doesn’t copy commits - it’s just a new pointer to the same commit.


Question 2: First Commit on Feature Branch

After creating feature/new-ui, you make a commit. What does the graph look like?

Before commit:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           main
                    feature/new-ui ← HEAD

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s
                              ↑            ↑
                           main     feature/new-ui

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s
                                           ↑
                                         main
                                  feature/new-ui ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           main

                          p9q8r7s
                              ↑
                    feature/new-ui ← HEAD

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s
                              ↑            ↑
                           main     feature/new-ui ← HEAD
Show Answer

Correct Answer: D

When you make a commit on a branch, Git creates a new commit and moves ONLY the current branch pointer forward. The main pointer stays at i7j8k9l because we’re not on the main branch. The new commit p9q8r7s becomes the new tip of feature/new-ui. Option A is wrong because HEAD should point to feature/new-ui. Option B is wrong because main moved (it shouldn’t). Option C is wrong because commits form a chain - the new commit has i7j8k9l as its parent.


Question 3: Multiple Commits on Feature Branch

You make two more commits on feature/new-ui. What’s the state now?

Starting from:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s
                              ↑            ↑
                           main     feature/new-ui ← HEAD

After 2 more commits:

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                                 main
                                                          feature/new-ui ← HEAD

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                           main                              feature/new-ui ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           main

                          p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                       ↑
                                              feature/new-ui ← HEAD

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  t1u2v3w  ←  x4y5z6a
                              ↑                        ↑
                           main                 feature/new-ui ← HEAD
Show Answer

Correct Answer: B

Each commit moves the current branch pointer forward. After two more commits, feature/new-ui points to x4y5z6a (the latest commit), while main remains at i7j8k9l (where we branched from). The commits form a linear chain: i7j8k9lp9q8r7st1u2v3wx4y5z6a. Option A is wrong because main shouldn’t move. Option C is wrong because it breaks the commit chain (p9q8r7s must have i7j8k9l as parent). Option D is wrong because it skips commit p9q8r7s in the chain.


Question 4: Switching to Main Branch

You run git checkout main. What happens to the pointers?

Before checkout:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                           main                              feature/new-ui ← HEAD

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                         main ← HEAD                          feature/new-ui

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                         main ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                         main ← HEAD

                          p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                       ↑
                                              feature/new-ui

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                            main ← HEAD
                                                            feature/new-ui
Show Answer

Correct Answer: A

git checkout (or git switch) ONLY moves the HEAD pointer. Branch pointers don’t change. HEAD moves from pointing to feature/new-ui to pointing to main. Both branches still exist and point to their respective commits. Your working directory changes to show the state at commit i7j8k9l. Option B is wrong because feature/new-ui still exists. Option C incorrectly shows the commits as separate chains. Option D is wrong because main is still at i7j8k9l, not x4y5z6a.


Question 5: Fast-Forward Merge

While on main, you run git merge feature/new-ui and Git performs a “fast-forward” merge. What’s the result?

Before merge:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                         main ← HEAD                          feature/new-ui

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  merge-commit
                                                                               ↑
                                                                          main ← HEAD
                                                                          feature/new-ui

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              main ← HEAD
                                                              feature/new-ui

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                         main ← HEAD                          feature/new-ui

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                         main ← HEAD
                         feature/new-ui
Show Answer

Correct Answer: B

A fast-forward merge moves the target branch pointer (main) forward to match the source branch (feature/new-ui). No merge commit is created because main just “catches up” to feature/new-ui. Both pointers now point to the same commit x4y5z6a. Option A is wrong because fast-forward doesn’t create a merge commit. Option C is wrong because main didn’t move. Option D is wrong because it loses all the feature commits.


Question 6: Adding a Tag

After the merge, you create a tag: git tag -a v1.0 -m "Release 1.0". Where does the tag pointer point?

Before tag:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              main ← HEAD
                                                              feature/new-ui

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                              ↑                                       ↑
                           (v1.0)                                main ← HEAD
                                                              feature/new-ui

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              main ← HEAD
                                                              feature/new-ui
                                                                 (v1.0)

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  v1.0-tag
                                                                               ↑
                                                                          main ← HEAD
                                                                          feature/new-ui

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l
                              ↑
                           (v1.0)
                           
                          p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                       ↑
                                                  main ← HEAD
                                                  feature/new-ui
Show Answer

Correct Answer: B

Tags are pointers to commits, just like branches. By default, git tag creates a tag pointing to the commit that HEAD currently references (which is x4y5z6a since HEAD → main → x4y5z6a). The tag, main, and feature/new-ui all point to the same commit now. Option A is wrong because the tag should point to the current HEAD commit. Option C is wrong because tags don’t create new commits. Option D incorrectly shows separated commit chains.


Question 7: Divergent Branches (Part 1)

You switch to main and make a commit. Meanwhile, feature/new-ui stays where it is. What’s the state?

Starting state:
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              main ← HEAD
                                                              feature/new-ui
                                                                 (v1.0)

After: git checkout main, then make a commit

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  b7c8d9e
                                                                   ↑            ↑
                                                           feature/new-ui  main ← HEAD
                                                              (v1.0)

B)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                           feature/new-ui
                                                              (v1.0)
                                                              
                                                             b7c8d9e
                                                                 ↑
                                                            main ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  b7c8d9e
                                                                   ↑            ↑
                                                           feature/new-ui  main ← HEAD
                                                              (v1.0)        feature/new-ui

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              (v1.0)
                                                           feature/new-ui
                                                            main ← HEAD
Show Answer

Correct Answer: A

When on main and making a commit, only the main pointer moves forward. The new commit b7c8d9e has x4y5z6a as its parent. feature/new-ui and the tag v1.0 remain pointing at x4y5z6a. This creates a linear history where main moved ahead. Option B is wrong because commits must have parents (b7c8d9e should have x4y5z6a as parent). Option C is wrong because feature/new-ui shouldn’t move (it shouldn’t appear twice). Option D is wrong because it shows no new commit was created - main is still at x4y5z6a instead of at the new commit b7c8d9e.


Question 8: Creating Divergent Branches

Starting from Question 7’s result, you now switch to feature/new-ui and make a new commit. What does the repository look like?

Starting state (from Q7):
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  b7c8d9e
                                                                   ↑            ↑
                                                              (v1.0)        main ← HEAD
                                                           feature/new-ui

Commands run:
  git checkout feature/new-ui
  echo "new feature code" >> app.js
  git add app.js
  git commit -m "Add new UI feature"

What's the result?

A)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  b7c8d9e  ←  f1g2h3i
                                                                   ↑            ↑            ↑
                                                              (v1.0)         main    feature/new-ui ← HEAD

B)

                                                                        b7c8d9e
                                                                            ↑
                                                                          main
                                                                           /
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←
                                                                   ↑      \
                                                              (v1.0)       f1g2h3i
                                                                              ↑
                                                                      feature/new-ui ← HEAD

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                              (v1.0)
                                                                   
                          b7c8d9e                             f1g2h3i
                              ↑                                   ↑
                            main                          feature/new-ui ← HEAD

D)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←  b7c8d9e
                                                                   ↑            ↑
                                                              (v1.0)         main
                                                                                ↖
                                                                                 f1g2h3i
                                                                                    ↑
                                                                            feature/new-ui ← HEAD
Show Answer

Correct Answer: B

The branches have diverged from their common ancestor x4y5z6a:

  1. Checkout moves HEAD: git checkout feature/new-ui moves HEAD from main to feature/new-ui (now at x4y5z6a)
  2. New commit on feature/new-ui: The commit creates f1g2h3i with parent x4y5z6a (where feature/new-ui was)
  3. Result: Both b7c8d9e (on main) and f1g2h3i (on feature/new-ui) branch from x4y5z6a

This creates a fork in history. The key insight: feature/new-ui was still pointing to x4y5z6a (it didn’t move when main got commit b7c8d9e in Q7), so the new commit f1g2h3i branches from x4y5z6a, NOT from b7c8d9e.

Why other options are wrong:

  • Option A: Shows linear history (f1g2h3i after b7c8d9e), but feature/new-ui should branch from x4y5z6a where it was, not from main’s new position
  • Option C: Disconnects commits from their parents (commits floating in space)
  • Option D: Shows f1g2h3i branching from b7c8d9e, but feature/new-ui was at x4y5z6a when we checked it out

Question 9: Checking Out a Commit (Detached HEAD)

You run git checkout x4y5z6a (the commit tagged v1.0). What state is Git in?

Before checkout:
                                                                        b7c8d9e
                                                                            ↑
                                                                        main ← HEAD
                                                                           /
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←
                                                                   ↑      \
                                                              (v1.0)       f1g2h3i
                                                                              ↑
                                                                      feature/new-ui

A)

                                                                        b7c8d9e
                                                                            ↑
                                                                       main ← HEAD
                                                                           /
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←
                                                                   ↑      \
                                                              (v1.0)       f1g2h3i
                                                                              ↑
                                                                      feature/new-ui

B)

                                                                        b7c8d9e
                                                                            ↑
                                                                          main
                                                                           /
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←
                                                        main ← HEAD ↑      \
                                                              (v1.0)       f1g2h3i
                                                                              ↑
                                                                      feature/new-ui

C)

  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a
                                                                   ↑
                                                                 HEAD
                                                              (v1.0) (detached)

D)

                                                                        b7c8d9e
                                                                            ↑
                                                                          main
                                                                           /
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a  ←
                                                             ↑   ↑      \
                                                           HEAD           f1g2h3i
                                                        (detached)           ↑
                                                              (v1.0)   feature/new-ui
Show Answer

Correct Answer: D

When you check out a specific commit (not a branch), HEAD points directly to that commit rather than to a branch pointer. This is called “detached HEAD” state. Git warns you because commits made in this state won’t belong to any branch.

Why D is correct:

  • HEAD now points directly to commit x4y5z6a
  • HEAD is marked as “(detached)” because it’s not pointing through a branch
  • The graph structure doesn’t change - branches stay where they were

Why other options are wrong:

  • Option A: Shows HEAD still attached to main (which stayed at b7c8d9e). Wrong! Checking out a commit hash detaches HEAD from branches
  • Option B: Shows both “main ← HEAD” label AND main pointing to x4y5z6a. Confusing and wrong - main didn’t move, only HEAD did
  • Option C: Missing the divergent commits (b7c8d9e and f1g2h3i). Checking out an old commit doesn’t delete newer commits!

Question 10: Renaming a Branch

You rename a branch with git branch -m old-name new-name. What actually changes?

Before rename:
                                                              ↱  b7c8d9e
                                                             /       ↑
  a1b2c3d  ←  e4f5g6h  ←  i7j8k9l  ←  p9q8r7s  ←  t1u2v3w  ←  x4y5z6a     main
                                                                   ↑  ↖
                                                              (v1.0)    f1g2h3i
                                                                           ↑
                                                                   feature/old-name ← HEAD

A) The commit f1g2h3i gets a new hash because the branch name is part of the commit

B) A new commit is created with the new branch name, and the old commit is deleted

C) Only the branch pointer’s name changes; the commit f1g2h3i and tag v1.0 are unchanged

D) The tag v1.0 is moved to the tip of the renamed branch to track the new name

Show Answer

Correct Answer: C

Renaming a branch only changes the branch pointer’s label. Git creates a new pointer with the new name pointing to the same commit, then deletes the old pointer. No commits are modified or created. Tags like v1.0 are unaffected because they point to commits, not to branch names. This is why renaming branches is safe and instant - you’re just changing a label, not touching the actual history. Option A is wrong because commit hashes are based on content, not branch names. Option B is wrong because no commits are created or deleted. Option D is wrong because tags point to commits and are independent of branch names.


Question 11: Understanding Remote-Tracking Branches

You run git branch -a and see this output. What are the three types of references shown?

$ git branch -a
  main
  feature/new-feature
  remotes/origin/main
  remotes/origin/feature/old-pr

A) All four are local branches that you can directly commit to

B) main and feature/new-feature are local branches; remotes/origin/main and remotes/origin/feature/old-pr are remote branches on GitHub

C) main and feature/new-feature are local branches where you work; remotes/origin/main and remotes/origin/feature/old-pr are local bookmarks showing GitHub’s state

D) remotes/origin/* are remote branches that you can commit to using git push

Show Answer

Correct Answer: C

Remote-tracking branches (like remotes/origin/main) are local copies that serve as bookmarks showing what exists on GitHub. They’re not the actual remote branches - they’re your local Git’s record of what was on GitHub last time you fetched. You can’t commit directly to them. Option A is wrong because remote-tracking branches are read-only bookmarks. Option B is wrong because they’re not remote branches - they’re local references to remote branches. Option D is wrong because you don’t commit to remote-tracking branches; they’re automatically updated by git fetch or git pull.


Question 12: What Happens After git fetch

You run git fetch origin. What does this command update?

Before fetch:
GitHub (origin):
  main → x4y5z6a (latest commit)

Your local Git:
  main → i7j8k9l (outdated)
  remotes/origin/main → i7j8k9l (outdated bookmark)

After fetch:

A) Only your local main branch updates to point to x4y5z6a

B) Only remotes/origin/main updates to x4y5z6a; your local main stays at i7j8k9l

C) Both main and remotes/origin/main update to x4y5z6a

D) Neither updates; you need git pull to update anything

Show Answer

Correct Answer: B

git fetch downloads new commits from GitHub and updates remote-tracking branches (remotes/origin/main), but it does NOT update your local branches. Your local main stays at i7j8k9l until you manually merge or use git pull (which is fetch + merge). This is the safe way to see what’s changed on GitHub without affecting your work. Option A is wrong because fetch doesn’t touch local branches. Option C is wrong because only the bookmark updates. Option D is wrong because fetch DOES update remote-tracking branches.


Question 13: Stale Remote-Tracking Branches

A PR was merged and the feature branch was deleted on GitHub. You run git branch -a locally. What do you see?

GitHub (origin):
  main (only branch that exists)

Your local Git hasn't fetched yet:

A)

  main
  remotes/origin/main

B)

  main
  remotes/origin/main
  remotes/origin/feature/old-pr  ← Still shows!

C)

  main
  feature/old-pr (automatically deleted)
  remotes/origin/main

D) Git automatically detects the deletion and removes remotes/origin/feature/old-pr

Show Answer

Correct Answer: B

Your local Git still has the remotes/origin/feature/old-pr reference because Git doesn’t automatically remove remote-tracking branches. They’re stale (pointing to a branch that no longer exists on GitHub) until you run git fetch --prune or git remote prune origin. This is intentional - Git errs on the side of keeping information. Option A is wrong because the stale reference persists. Option C is wrong because local branches aren’t automatically deleted. Option D is wrong because Git doesn’t auto-detect deletions without fetching.


Question 14: Understanding git fetch –prune

What does git fetch --prune do differently from git fetch?

Situation:
- GitHub deleted feature/old-pr
- Your local Git still has remotes/origin/feature/old-pr

You run: git fetch --prune

A) Downloads new commits and force-deletes your local feature/old-pr branch

B) Downloads new commits and removes the stale remotes/origin/feature/old-pr reference

C) Only removes stale remote-tracking branches without downloading new commits

D) Deletes both the local branch and remote-tracking branch for feature/old-pr

Show Answer

Correct Answer: B

git fetch --prune does TWO things: (1) downloads new commits/branches from GitHub, and (2) removes remote-tracking branches that no longer exist on GitHub. It does NOT touch your local branches - you must delete those separately with git branch -d. Option A is wrong because local branches aren’t affected by prune. Option C is wrong because --prune is an addon to fetch, not a replacement. Option D is wrong because local branches are never automatically deleted.


Question 15: git pull –prune Workflow

You just merged a PR on GitHub and the feature branch was auto-deleted. You run git checkout main then git pull --prune. What happens?

Before:
GitHub: main → x4y5z6a (has merged PR)
        feature/old-pr deleted ✅

Local:  main → i7j8k9l (outdated)
        feature/old-pr → p9q8r7s (still exists locally)
        remotes/origin/main → i7j8k9l (outdated)
        remotes/origin/feature/old-pr → p9q8r7s (stale!)

After git pull --prune:

A)

Local:  main → x4y5z6a (updated)
        remotes/origin/main → x4y5z6a (updated)

B)

Local:  main → x4y5z6a (updated)
        feature/old-pr deleted
        remotes/origin/main → x4y5z6a (updated)

C)

Local:  main → x4y5z6a (updated)
        feature/old-pr → p9q8r7s (still exists)
        remotes/origin/main → x4y5z6a (updated)

D)

Local:  main → i7j8k9l (unchanged)
        remotes/origin/main → x4y5z6a (updated)
        remotes/origin/feature/old-pr deleted
Show Answer

Correct Answer: C

git pull --prune combines three actions: (1) git fetch --prune (download + remove stale remote-tracking branches), (2) merge into current branch (main fast-forwards to x4y5z6a). Your LOCAL feature/old-pr branch is NOT deleted - you must do that separately with git branch -d feature/old-pr. Only the remote-tracking branch remotes/origin/feature/old-pr is removed by --prune. Option A is wrong because it doesn’t show the local feature branch. Option B is wrong because local branches aren’t auto-deleted. Option D is wrong because main DOES update (that’s what pull does).


Question 16: The Bookmark Analogy

According to the lecture’s “bookmark analogy,” what do remote-tracking branches represent?

GitHub (the websites) has:
  - main branch
  - feature/xyz branch

Your local Git has:
  - Local branches (main, feature/xyz)
  - Remote-tracking branches (remotes/origin/main, remotes/origin/feature/xyz)

A) Remote-tracking branches ARE the actual remote branches, just with a different name

B) Remote-tracking branches are like bookmarks in your browser - they point to where GitHub’s branches were last time you checked

C) Remote-tracking branches are backups of your local branches in case you lose your work

D) Remote-tracking branches are temporary references that disappear after you merge

Show Answer

Correct Answer: B

The lecture compares remote-tracking branches to browser bookmarks: GitHub is like actual websites, and remote-tracking branches are your local bookmarks pointing to GitHub’s branches. Just like bookmarks can become outdated if a website changes, remote-tracking branches become stale if GitHub’s branches change without you fetching. Option A is wrong because they’re local copies, not the actual remote branches. Option C is wrong because they track remote state, not local backups. Option D is wrong because they persist until explicitly pruned.


Question 17: Preventing Stale References

You want Git to automatically remove stale remote-tracking branches every time you fetch. What should you configure?

A) git config --global fetch.prune true

B) git config --global branch.autocleanup true

C) git config --global remote.pruneOnFetch true

D) git branch --set-upstream-to=origin/main

Show Answer

Correct Answer: A

Running git config --global fetch.prune true makes every git fetch and git pull automatically clean up stale remote-tracking branches. This is the recommended setup from the lecture because it’s “one less thing to remember.” Option B is not a valid Git config. Option C is not the correct config name. Option D sets upstream tracking for branches, which is unrelated to pruning.


Question 18: Checking Merged Branches

You want to see which local branches have been merged into main before deleting them. What command shows this?

A) git branch --merged main

B) git branch --no-merged

C) git remote prune origin --dry-run

D) git log --merged

Show Answer

Correct Answer: A

git branch --merged main lists all local branches whose commits are reachable from main (meaning they’ve been merged). You can safely delete these with git branch -d. Option B shows branches NOT yet merged (opposite of what you want). Option C shows remote-tracking branches that would be pruned, not local branches. Option D is not a valid git log flag.


Question 19: Squash Merge Branch Deletion

Your PR was merged with “Squash and merge” on GitHub. The branch was deleted there. Now you try to delete your local branch:

$ git branch -d feature/squashed
error: The branch 'feature/squashed' is not fully merged.

Why does Git say this, and what should you do?

A) Git is wrong; run git branch -D feature/squashed (force delete) after confirming the PR was merged

B) The PR wasn’t actually merged; check GitHub again

C) You must first run git pull --rebase to sync the squashed commit

D) Local branches can’t be deleted if they were squash-merged; leave it

Show Answer

Correct Answer: A

“Squash and merge” creates a NEW commit with all your changes combined, rather than using your original commits. Git sees your local commits as “not merged” because they don’t exist in main’s history (only the squashed version does). After confirming on GitHub that the PR was indeed merged, it’s safe to force delete with git branch -D feature/squashed. Option B is wrong - the PR IS merged, just in a different form. Option C is wrong - rebase won’t help here. Option D is wrong - you can and should delete merged branches.


Question 20: Complete Cleanup After PR Merge

Your PR was merged using “Create a merge commit” (not squash) and GitHub auto-deleted the remote branch. What’s the complete cleanup workflow?

Starting state:
- GitHub: main (updated with your PR using merge commit), feature/xyz deleted
- Local: main (outdated), feature/xyz (still exists),
         remotes/origin/feature/xyz (stale)

A)

git checkout main
git branch -d feature/xyz

B)

git fetch --prune
git checkout main
git pull

C)

git checkout main
git pull --prune
git branch -d feature/xyz

D)

git remote prune origin
git branch -D feature/xyz
Show Answer

Correct Answer: C

The complete workflow is: (1) git checkout main to switch to main, (2) git pull --prune to update main AND remove stale remote-tracking branches, (3) git branch -d feature/xyz to delete your local branch. This cleans up all three: local branch, local main, and stale remote-tracking references. Since the PR was merged with “Create a merge commit” (not squash), Git recognizes the branch as merged and -d works safely. Option A is wrong because it doesn’t update main or prune. Option B is wrong because it doesn’t delete the local branch. Option D is wrong because it doesn’t update main, and uses force delete (-D) which is unnecessary when the branch was properly merged.


Scoring Guide


Key Takeaways to Remember

  1. Branches are pointers - They’re lightweight references to commits, not copies of commits
  2. HEAD shows your location - HEAD points to your current branch (or commit in detached state)
  3. Creating a branch is cheap - It’s just creating a new pointer, no files are copied
  4. Only the current branch moves - When you commit, only the branch HEAD points to moves forward
  5. Switching branches moves HEAD - git checkout/git switch only moves the HEAD pointer
  6. Tags are permanent pointers - Unlike branches, they don’t move when you commit
  7. Fast-forward vs three-way merge - Fast-forward when linear history; three-way when diverged
  8. Merge commits have two parents - This is what makes the history non-linear
  9. Deleting a branch removes the pointer - Commits remain if they’re reachable from other branches
  10. Detached HEAD is direct commit reference - HEAD points to a commit, not a branch
  11. Three types of branches - Local branches (where you work), remote-tracking branches (local bookmarks of GitHub state), and actual remote branches (on GitHub)
  12. Remote-tracking branches are bookmarks - They’re local references showing GitHub’s state at last fetch
  13. git fetch updates bookmarks - Downloads commits and updates remote-tracking branches, but not local branches
  14. Stale references need pruning - Use git fetch --prune to remove remote-tracking branches for deleted remote branches
  15. Enable automatic pruning - Run git config --global fetch.prune true to always clean up stale references
  16. Complete cleanup workflow - After PR merge: git checkout main, git pull --prune, git branch -d feature/xyz
  17. Squash merges need force delete - After squash merge, use git branch -D because Git doesn’t recognize the merge
  18. Local branches must be manually deleted - Pruning only affects remote-tracking branches, not local branches

Practice Recommendation

After completing this exercise, try these commands in a test repository:

Part 1: Local Branches and Pointers

# Create a test repository
git init test-branches
cd test-branches

# Make some commits and branches
echo "file1" > file.txt && git add . && git commit -m "commit 1"
echo "file2" > file.txt && git add . && git commit -m "commit 2"
git checkout -b feature
echo "file3" > file.txt && git add . && git commit -m "commit 3"

# Visualize the graph
git log --oneline --graph --all --decorate

# Experiment with switching branches and making commits
# Watch how the pointers move!

Part 2: Remote-Tracking Branches (Practice with a GitHub Repository)

# Clone one of your GitHub repositories
git clone https://github.com/yourusername/yourrepo.git
cd yourrepo

# View all branches (including remote-tracking)
git branch -a

# Create and push a feature branch
git checkout -b test-cleanup
echo "test" > test.txt && git add . && git commit -m "test"
git push -u origin test-cleanup

# Simulate PR merge: Go to GitHub, merge the PR, delete the branch

# Now back in your terminal - see the stale reference
git branch -a  # Still shows remotes/origin/test-cleanup

# Clean up properly
git checkout main
git pull --prune  # Updates main AND removes stale reference
git branch -d test-cleanup  # Deletes local branch

# Verify cleanup
git branch -a  # Should be clean!

# Enable automatic pruning for future
git config --global fetch.prune true

This hands-on practice will solidify your understanding of the concepts tested in this exercise, especially the difference between local branches and remote-tracking branches!

© 2026 Dominik Mueller   •  Powered by Soopr   •  Theme  Moonwalk