Skip to content

Search is only available in production builds. Try building and previewing the site to test it out locally.

Test MDX File V9

This virtual lab lets you run the four most common Git commands and watch what they actually do. There is one file, hello.txt, and you move it through four stages. Working Directory — where you edit files on your computer. Staging Area — a holding area for changes you’ve marked as ready to commit. Local Repo — your personal commit history (HEAD points to the newest commit). Remote Repo — the shared copy on a server, e.g. GitHub.

What the commands do

  • Edit hello.txt in the text area. The file card turns modified.
  • git add — copies the working-directory version of the file into the staging area.
  • git commit — type a message, then click. The staged version is recorded as a new commit on the local repo.
  • git push — uploads local commits to the remote.
  • git pull — downloads remote commits to the local repo.

Try this sequence:

  1. Edit hello.txt.
  2. git addgit commit (with a message) → git push.
  3. Click 👥 Teammate pushes to simulate someone else committing to the remote.
  4. git pull to bring their changes down to your local repo.
  5. Now edit the file again, commit, and try git push before pulling — you’ll see the real “Push rejected — pull first” error. Run git pull, then push again.

Notes:

  • Buttons grey out when there’s nothing to do (e.g., git add when nothing has changed). Hover for the reason.
  • The What happened panel narrates every command in plain English — read it after each click.
  • The dots near the bottom show whether your local or remote is ahead.
  • Click ↻ Reset to start over.

Git Workflow Lab

Click commands to move hello.txt through the four stages and watch how add, commit, push and pull actually behave.

Local Repository
Remote
Working Directory
edit files here
hello.txt
clean
Hello, world!
Staging Area
the index
Nothing staged.
Edit the file, then run git add.
Local Repo
HEAD → main
HEAD
49536c2
Initial commit
Hello, world!
Remote Repo
origin/main
HEAD
49536c2
Initial commit
Hello, world!
Commands
local =remote =
What happenedlast 1 entry
Repo initialised. Working directory, staging area and local repo all match the remote.

Try this sequence: editgit addgit commitgit push. Then click 👥 Teammate pushes and try git pull.

Now that you’ve seen how add, commit, push and pull move a single line of work between the working directory, staging area, local repo and remote, it’s time for the next idea: doing more than one thing at once. Branches let you split a project’s history so you can develop a new feature, try an experiment, or apply a hotfix without disturbing the work everyone else is doing on main. Merging is how those parallel histories come back together. This is sometimes clean, sometimes not.

The lab below renders the local repository as a left-to-right commit graph, with each branch on its own horizontal “lane”. The remote panel on the right is your GitLab origin: branches only appear there once you push them. As you create branches, switch between them, commit, and merge, watch how the graph changes shape — that shape is what git log --graph is showing you on the command line.

Work through these in order. After each one, glance at the What happened panel at the bottom as it explains what each command did, in plain English.

  1. Make a branch and switch to it. From the fresh starting state (press “reset”), type a name like feature/login into the branch field and click git branch. Notice that HEAD doesn’t move as you’ve created a label, but you’re still on main. Now use git switch to move onto the new branch.
  2. Commit on a branch. With HEAD on your feature branch, make two commits. Watch how only the feature lane grows; main sits still on its own commit. Use “git push origin” to publish the branch to GitLab. Switch back to main and then merge the branch into main. Notice that the HEAD is now on the feature branch. If you push now you can publish this update to GItLab.

The mental model

Branches are not folders or copies of the code. A branch is a movable label that points at a single commit. git branch creates a label; git switch moves HEAD to a different label; committing advances whichever label HEAD is currently riding. The graph is the truth and the labels are just convenient names for spots on it.

Git Branching Lab

Create branches, switch between them, and watch git merge handle fast-forwards, three-way merges, and conflicts. Push branches to GitLab so they're ready for a merge request.

Local Repository1 branch
HEAD → main
3fd0mainHEAD
GitLab — origin
0 branches pushed
No commits here yet — push a branch to publish it.
Commands
on branch main at 3fd0c1e
·
Merge into main:
·
Preset scenarios
jump straight to a teaching moment
What happenedlast 1 entry
Repository initialised on branch main with one commit. Ready to branch.

Try this: load Diverged branches, switch to main, run git merge feature — watch a merge commit appear with two parents.

Now try some presets:

  1. Fast-forward merge. Load the Feature ready to fast-forward preset. You’re on main (i.e., HEAD), and feature is two commits ahead. Run git merge feature. The main pointer slides forward to meet feature — no merge commit is created, because main had no commits of its own to combine.
  2. Three-way merge. Load the Diverged branches preset. Now both branches have new commits, so a fast-forward isn’t possible. Run git merge feature from main and look closely at the resulting commit: it has two parent edges feeding into it. That’s a merge commit, and it’s how Git records “these two histories came back together here”.
  3. Resolve a conflict. Load the Merge conflict ahead preset. Both branches edited the same line of README differently. When you run git merge feature, the merge pauses and a red panel appears with the file showing <<<<<<<, ======= and >>>>>>> markers — exactly what you’d see in a real editor. Try the Keep ours, Keep theirs and Keep both shortcut buttons to see what each does, then commit to complete the merge.
  4. Publish a branch to GitLab. With a feature branch checked out, click git push origin. The branch appears in the right-hand origin panel with the prefix origin/feature/login. In a real workflow this is the moment you’d open a merge request on GitLab.
  5. Clean up. Once a feature branch has been merged into main, you can safely delete the local label with git branch -d. The commits don’t disappear — they’re still reachable from main — but the branch pointer is gone. Try deleting an unmerged branch and read the error: Git protects you from losing work.

Account Lab

C++ Class Object Lab

Drag a class onto the stack and watch the object's bytes lay out — fields, padding, inherited base and all.

Stack — main()0x7FFFFFC00x7FFFFFFF
40 / 64 bytes used24 free

64-bit platform, double-aligned. Account is 16 bytes (4 + 4 padding + 8); DepositAccount and CurrentAccount add 8 more, so 24 each.

+0
+8
+10
+18
+20
+28
+30
+38
E8
E9
EA
EB
EC
ED
EE
EF
F0
F1
F2
F3
F4
F5
F6
F7
F8
F9
FA
FB
FC
FD
FE
FF
a:Account
accountNumber
12345
pad
balance
100.00
b:DepositAccount
inherited from Account
accountNumber
12345
pad
balance
100.00
interestRate
2.50
Account (own object)derived class (own fields)inherited basealignment padding

Class Palette — drag onto the stack

Account16B
DepositAccount24B
CurrentAccount24B
main.cpp — live
Account a{12345, 100.00}; // 16B at 0x7FFFFFC0
DepositAccount b{12345, 100.00, 2.50}; // 24B at 0x7FFFFFD0
cout << a.accountNumber; // output: 12345
cout << a.balance; // output: 100.00
cout << b.accountNumber; // output: 12345 (from Account)
cout << b.balance; // output: 100.00 (from Account)
cout << b.interestRate; // output: 2.50
Try this:Notice the 4-byte gap between accountNumber and balance — that's alignment padding so the double can sit on an 8-byte boundary. Now drag a DepositAccount onto the stack and watch its first 16 bytes form an inherited Account sub-block, with interestRate appended after. Click any object to edit its fields. The next lab takes the same objects but allocates them on the heap with new — same layout, very different lifetime story.

Heap Lab

C++ Heap Allocation Lab

new on the heap, virtual dispatch through the vtable, and the three classic heap bugs.

Stack — main()3 × Account* (8B each)
0x7FFFFFD0
0x7FFFFFE0a=nullptr
0x7FFFFFD8b=nullptr
0x7FFFFFD0c=nullptr
Heapgrows on each new
0x005580A0
Heap is empty. Use the controls below to call new.
.rodata — vtablesstatic · read-only
0x004012F0
No vtables yet — they appear when their class is first used.

One vtable per class with virtual methods. Each row is a function pointer the compiler emits at compile time. At a virtual call, the object's __vptr is followed here to pick the right implementation — that's how a->display() dispatches to the derived class even through a base-class pointer.

Pointer Actions — the program is live; each click is one statement

Account* anullptr
Account* bnullptr
Account* cnullptr
main.cpp — transcript
// no statements yet — pick an action above
Try this:Set a = new DepositAccount(...) and watch a->display() dispatch through the vptr to DepositAccount::display — the static type of a is Account* but the right method runs. Then alias b = a so two pointers share one block, delete a — both a and b turn red (dangling). Now click delete b for a textbook double-delete.