Skip to content
GitTree

Lesson 11 · Everyday work

Fetch a teammate's change without replacing your page

Receive Leo's real footer commit while keeping main, the index and the original working page unchanged. Then inspect stale-ref pruning in a separate replay so server deletion is not confused with local cleanup.

Progress saved in this browser.

Playing loads the video from YouTube (privacy-enhanced mode).

English narration · English and Arabic captions

Open the video pageWatch on YouTube

What you will learn

  • Explain why a fetched remote-tracking ref can advance while main does not.
  • Compare the fetched footer without checking it out or integrating it.
  • Predict fetch behavior when the working page has an overlapping local edit.
  • Distinguish pruning a local stale ref from deleting a server or local branch.

Before you start

Start where lesson 10 ended: the original main/H6 checked out, six commits including docs/remotes.md, clean, tracking origin/main/H6. The separate local bare origin has only main/H6. Feature/pricing-cards/F1 remains local, without upstream or publication. Keep the demo's background fetch off (repo.autoFetchInterval = 0) to capture a genuine before/after. Do not use lesson 4's supplemental clone.

Use a new sibling gittree-features-leo for the teammate; stop if the destination already exists. All repositories are disposable copies of GitTree Features, outside every source checkout. The video was recorded with Git 2.52.0 and GitTree 2.0 on Ubuntu 24.04: Leo's commit and push, the stale-ref copy's preparation and the checks ran in the terminal; the fetch, the graph, Compare References, the file views and Prune Remote were done in the app. Nothing was run on macOS or Windows, and Ubuntu is the only Linux system recorded. GitTree's source floor is Git 2.39.0. No provider, Pro/trial or API credentials are needed for this local Git transport.

Concept

Fetch obtains objects and updates fetched knowledge. Here the server's main advances to Leo's H7, but the original's origin/main remains H6 until fetching. A zero-behind count against a stale origin/main is not evidence the server is unchanged.

After fetch, origin/main names H7 while local main and HEAD stay H6. The index and working page remain H6 too. Reading the footer diff is inspection, not Pull, checkout, merge or rebase. “Behind one” measures ancestry, not how many files or lines differ.

Pull is fetch plus a second step. git pull runs a fetch and then integrates what arrived into your current branch (a fast-forward, a merge or a rebase). Fetch alone stops after the first half, which is why it can never change your files. Lesson 12 chooses the second step on purpose.

Pruning removes remote-tracking refs whose corresponding server branch is gone, according to the fetch/refspec rules. It does not itself delete that server branch, erase a local branch or remove every tag. The source's Fetch All request already enables pruning; its native equivalent below therefore includes --prune. Prune Remote is a separate named-remote action, demonstrated only in a separate prepared stale-ref copy.

State effects

StepOriginal HEAD / mainIndex / workorigin/mainSeparate server main
InputH6H6 pageH6H6
Leo commits and pushes from his cloneH6UnchangedH6, now staleH7
Original Fetch AllH6UnchangedH7H7
Inspect diffH6UnchangedH7H7

No original notebook commit is added: the real project operation is the fetched ref update. The local feature still points at F1.

Full file inputs

In Leo's clone only, replace index.html with the complete first body. His subject is docs: add Leo's review reminder; author/committer Leo Okafor <leo@example.com>. The changed-input body is a separate original-copy working edit, not a second canonical commit.

File excerpt · html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>GitTree Features — course demo</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <a href="#main">GitTree Features</a>
  </header>
  <main id="main">
    <section class="hero" aria-labelledby="hero-title">
      <p class="eyebrow">GitTree Learn demo project</p>
      <h1 id="hero-title">See your work clearly.</h1>
      <p id="hero-copy">Choose one change, then check what Git saved.</p>
    </section>
    <section class="features" aria-labelledby="features-title">
      <h2 id="features-title">Follow your work</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>History</h3>
          <p>Read commits and branches together.</p>
        </article>
        <article class="feature-card">
          <h3>Changes</h3>
          <p>Review the exact content selected for a commit.</p>
        </article>
        <article class="feature-card">
          <h3>Recovery</h3>
          <p>Inspect the scope of a recovery point before using it.</p>
        </article>
      </div>
    </section>
  </main>
  <footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
  <script type="module" src="site.js"></script>
</body>
</html>

Separate dirty-fetch replay — HTML-DIRTY-FETCH

This full body is for the separate changed-input replay only, never the canonical original.

File excerpt · html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>GitTree Features — course demo</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <a href="#main">GitTree Features</a>
  </header>
  <main id="main">
    <section class="hero" aria-labelledby="hero-title">
      <p class="eyebrow">GitTree Learn demo project</p>
      <h1 id="hero-title">See your work clearly.</h1>
      <p id="hero-copy">Inspect the update before integrating it.</p>
    </section>
    <section class="features" aria-labelledby="features-title">
      <h2 id="features-title">Follow your work</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>History</h3>
          <p>Read commits and branches together.</p>
        </article>
        <article class="feature-card">
          <h3>Changes</h3>
          <p>Review the exact content selected for a commit.</p>
        </article>
        <article class="feature-card">
          <h3>Recovery</h3>
          <p>Inspect the scope of a recovery point before using it.</p>
        </article>
      </div>
    </section>
  </main>
  <footer><p>Built by a fictional team for GitTree Learn.</p></footer>
  <script type="module" src="site.js"></script>
</body>
</html>

In GitTree

  1. Open the original main tab; inspect its repository identity and clean status. Confirm the background-fetch override remains0. Do not change the source checkout or automatically fetch before the before-state is captured.
  2. Prepare Leo's clone and exact footer commit with T1 below, explicitly labeled native teammate preparation. His push updates the local bare server, not the original's fetched record. No hosted account or simulated provider response is involved.
  3. Before fetching, run T2. Main and origin/main still agree at H6, even though direct server lookup names a different actual SHA. The working page still has the old footer.
  4. Open the palette with Command+Shift+P (Ctrl+Shift+P on Ubuntu) and choose Fetch All once; Command+Shift+F (Ctrl+Shift+F) is the shortcut. Wait for the real operation and result; do not click Pull. With one origin, right-click origin → Fetch Remote is an equivalent, not a second required fetch (it was not filmed).
  5. In the graph select the newly fetched commit, docs: add Leo's review reminder, and inspect the real subject and Leo metadata. The local main/HEAD label stays at its earlier commit. Selecting a graph row is not checkout.
  6. Palette Compare References… opens Compare References. Old side = main; New side = origin/main; What to compare = The two endpoints; choose Compare. Expect index.html only, with the exact added footer reminder. Do not use merge-base/log-set terminology for this endpoint-tree comparison.
  7. Show Files (Command+Shift+E, Ctrl+Shift+E on Ubuntu); select working index.html and Enter. Its footer is still the original. Choose Back to Graph, then palette Show Working Changes: staged/unstaged lists remain empty. No local save, commit or integration is required.
  8. End on main with six commits, origin/main at seven, count0/1 and clean work/index. Keep the unpublished local feature. Do not “fix” being behind by forcing a push.
  9. Separate stale-ref replay only: prepare B as described below, not the original. Run native prune dry-run first. Open B from New Tab (Ctrl+T) with its Open gittree-features-prune row under Recent repositories. In B's tab, right-click its named origin in the side panel → Prune Remote. The app dispatches that action directly; no preview or confirmation dialog is invented. Observe origin/practice/stale disappear while local keep-stale and all working bytes remain.

The Command-key chords are from the app's keymap; the Ctrl forms were the ones used on Ubuntu. The teammate and server preparation is native work in the terminal, not an app-created hosted project.

In the terminal

All commands below start in the original isolated gittree-features unless explicitly a -C command. Native original-fetch commands are alternatives to the app action, not mutations to repeat after it.

T1 — real teammate preparation

Command · bash
git clone --quiet --branch main "$(git remote get-url origin)" ../gittree-features-leo
git -C ../gittree-features-leo config user.name "Leo Okafor"
git -C ../gittree-features-leo config user.email leo@example.com
git -C ../gittree-features-leo config commit.gpgsign false

The new clone exists, main is checked out and only its local identity is changed. In that clone, change only the footer line so the whole file equals HTML-LEO-FOOTER (the video does it with one sed command; saving the complete body in an editor gives the same file), then:

Command · bash
git -C ../gittree-features-leo add -- index.html
git -C ../gittree-features-leo commit --quiet -m "docs: add Leo's review reminder"
git -C ../gittree-features-leo push --quiet origin main

All succeeded silently. This is a real Git push to the throwaway local bare origin; no internet account or production data was touched.

T2 — distinguish stale local knowledge from server state

Command · bash
git rev-list --left-right --count main...origin/main
git rev-parse refs/heads/main
git rev-parse refs/remotes/origin/main
git ls-remote --heads origin refs/heads/main

The count printed:

Output
0	0

The next two SHA outputs are equal H6 identities; ls-remote prints the actual different H7 SHA plus refs/heads/main. SHAs vary with commit metadata, so no fixed fake hash is printed here. This direct server query does not update origin/main.

T3 — fetch without integration and verify

Command · bash
git fetch --all --prune --quiet

Observed: exit 0, no stdout. GitTree's source enables prune on this request; the command mirrors that choice.

Command · bash
git symbolic-ref --short HEAD
git rev-list --count main
git rev-list --count origin/main
git rev-list --left-right --count main...origin/main
git log -1 --format="%s%n%an <%ae>%n%cn <%ce>" origin/main
git diff --name-only main origin/main
git status --short

Outputs before the final status, with the three-line metadata result grouped:

Output
main
6
7
0	1
docs: add Leo's review reminder
Leo Okafor <leo@example.com>
Leo Okafor <leo@example.com>
index.html

Final short status is empty exit 0. Main's SHA, full index.html in the index, and its full disk bytes were compared before/after and remained identical. Neither fetch nor graph inspection checked out H7.

Command · bash
git diff main origin/main -- index.html

Complete observed diff:

Output
diff --git a/index.html b/index.html
index eebd082..1e4cfde 100644
--- a/index.html
+++ b/index.html
@@ -34,7 +34,7 @@
       </div>
     </section>
   </main>
-  <footer><p>Built by a fictional team for GitTree Learn.</p></footer>
+  <footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
   <script type="module" src="site.js"></script>
 </body>
 </html>

T4 — changed input: local dirty page

Only in a separate same-project copy of the pre-fetch original, save full HTML-DIRTY-FETCH without staging. Leo's server H7 already exists:

Command · bash
git fetch --all --prune --quiet
git status --short
git show :index.html
git rev-list --left-right --count main...origin/main

Fetch succeeds; status:

Output
 M index.html

The full git show output remains the old recorded/index file, not the dirty working edition. Final counts are0/1. The working disk file remains exactly HTML-DIRTY-FETCH. An overlapping filename does not by itself create a fetch conflict; integrating later has different preconditions. The video compares the index and the working file with grep -n 'hero-copy\|<footer>' on each instead of printing the whole file; the replay's own check confirmed the working file equals HTML-DIRTY-FETCH.

T5 — stale remote-tracking ref, separate B

Create an isolated same-project B original and a separate B bare destination with server main/H7. Point B only at that destination using its measured file URL. Do not retarget A.

From the original demo folder, prepare two new nonexistent sibling destinations. These commands clone the same project into B and its own server, never retargeting A:

Command · bash
git clone --quiet --bare --single-branch --branch main --no-local ../gittree-features-origin.git ../gittree-features-prune-origin.git
git clone --quiet --single-branch --branch main --no-local . ../gittree-features-prune
PRUNE_URL="$(node --input-type=module -e "import path from 'node:path'; import {pathToFileURL} from 'node:url'; console.log(pathToFileURL(path.resolve('../gittree-features-prune-origin.git')).href);")"
git -C ../gittree-features-prune remote set-url origin "$PRUNE_URL"
git -C ../gittree-features-prune config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git --git-dir=../gittree-features-prune-origin.git branch practice/stale main
git -C ../gittree-features-prune fetch --prune --quiet origin
git -C ../gittree-features-prune branch keep-stale origin/practice/stale
git --git-dir=../gittree-features-prune-origin.git branch --delete --quiet practice/stale

The single-branch B clone initially fetches only main. Its explicit remote.origin.fetch assignment restores the original demo's wildcard branch mapping so practice/stale can be fetched; it changes B only. Stop on any failed preparation command. Set B's repo-specific background-fetch interval to 0 before the actual-app take. The disposable server branch is now absent, while B still has its fetched record and a separate local keep-stale branch. The following commands explicitly target B:

Command · bash
git -C ../gittree-features-prune remote prune --dry-run origin
git -C ../gittree-features-prune remote prune origin
git -C ../gittree-features-prune for-each-ref --format='%(refname)' refs/remotes/origin/practice/stale
git -C ../gittree-features-prune show-ref --verify --quiet refs/heads/keep-stale

Observed preview excerpt after its variable URL line:

Output
 * [would prune] origin/practice/stale

Observed execution excerpt:

Output
 * [pruned] origin/practice/stale

The for-each-ref is empty exit 0; show-ref is silent exit 0, proving local keep-stale still exists. B's main SHA and working page stay unchanged; server main remains H7. The full native transcripts include Pruning origin and the measured file URL; those machine-specific paths are not fabricated here.

Do not insert a normal Fetch All between stale-ref preparation and Prune Remote: Fetch All already prunes, leaving no stale candidate for the separate demonstration.

Result

Where you end: original main/H6 is still checked out with six commits and the old footer; origin/main/H7 records Leo's seventh commit; server main/H7 unchanged by fetch; main tracks origin/main and is one behind. Index/work clean; feature/pricing-cards/F1 still local/unpublished. B/C branches, dirty text and pruning preparation stay out of A. There is no extra docs/fetch-and-prune.md commit.

Common mistakes

  • Calling the pre-fetch0/0 count current server truth.
  • Expecting the fetched footer to replace the working page automatically.
  • Using Pull or checkout to make a fetch recording look successful.
  • Expecting a dirty page to be discarded or conflicted merely by fetch.
  • Interpreting prune as deleting the remote's repository or local keep-stale.

If something goes wrong

A missing folder, wrong URL or permission failure means inspect the intended origin and actual error, not reset history or overwrite the destination. Network/helper/trust refusal is not evidence of zero updates; record its actual build/message and resolve only the stated cause. Restricted mode can refuse transport; trust only the reviewed disposable lab, never a random repository to get past the film.

If original main moved or the footer changed, stop and inspect whether Pull, checkout or an external edit ran. Do not hard-reset to disguise the cause. Preserve the unexpected state before preparing a fresh demo checkpoint.

If no stale ref remains, check whether an earlier Fetch All already pruned it. Reprepare B; do not invent a disappearing row or delete a useful server branch.

Check your understanding

Answer each question, then read why. Questions marked “Required” count toward completing the lesson.

  1. Question 1 of 6

    Leo pushed H7, but you have not fetched. What may origin/main still name?

    Choose one answer.

  2. Question 2 of 6

    Which observations belong to the canonical fetch result?

    Choose every answer that applies.

  3. Question 3 of 6

    After fetch, main has6 and origin/main7 with H6 as parent of H7. What is main...origin/main count?

    Choose one answer.

  4. Question 4 of 6

    Change the input: save HTML-DIRTY-FETCH without staging, then fetch H7. What happens?

    Choose one answer.

  5. Question 5 of 6

    B's server branch was deleted, but B has origin/practice/stale and local keep-stale. What does pruning remove?

    Choose one answer.

  6. Question 6 of 6

    Which checks are required together?

    Choose every answer that applies.

0 of 6 correct

You answered every required question correctly.

Checked in this browser.

Practice

Predict the two original page versions after fetching: index and work both remain H6, while the new remote tree holds Leo's footer. In the separate dirty replay, verify full disk text survives and no conflict is created. In B, explain why keep-stale survives pruning. End only the original at the clean0/1 checkpoint.

Your own confirmation: the site cannot see your computer.

To complete the lesson, answer the required questions correctly and confirm the practical exercise.

Recap

  • Fetch refreshes local knowledge without integrating the branch.
  • Clean status does not mean up to date with the remote.
  • Pruning local tracking refs is distinct from deleting local or server branches.

Glossary terms introduced

Fetch — جلب; prune — تشذيب; stale remote-tracking ref — مرجع تتبُّع بعيد قديم; behind — متأخر; endpoint comparison — مقارنة الطرفين.

Video transcript

The narration of the video, cue by cue.

Show the transcript
  1. Receive the update without replacing your current page.
  2. Keep background fetching off for this before-and-after take.
  3. Prepare Leo's separate clone with a fictional local identity.
  4. Leo records and pushes the footer reminder to the local origin.
  5. The server moved while your fetched record stayed behind.
  6. These counts use your local fetched ref, not a live server snapshot.
  7. Which ref will move, and which file version will stay?
  8. Fetch all configured remotes; here there is only origin.
  9. Wait for Git's result before treating the update as received.
  10. Selecting Leo's commit does not check it out.
  11. Compare main with the fetched tree without moving either ref.
  12. The fetched tree has the reminder; your working page still does not.
  13. The original working file keeps its old footer.
  14. Clean working changes do not mean your branch is up to date.
  15. Verify six local commits, seven fetched commits and one behind.
  16. Fetching updated knowledge without integrating the file contents.
  17. A local edit in the same file survives this fetch.
  18. The server branch is already gone before this pruning example.
  19. Preview the stale tracking ref before removing it.
  20. Remove the stale local tracking ref, not the local rescue branch.
  21. The local branch and working page remain intact.
  22. A prior fetch may already have removed the stale tracking ref.
  23. Keep the original clean and behind one; do not pull or force-push.
  24. Next, inspect the destination before publishing a branch.