{"checkpoints":{"s-git-1":[{"q":"<p>You run <code dir=\"ltr\">git add index.html</code>, edit <code dir=\"ltr\">index.html</code> again, then run <code dir=\"ltr\">git commit -m &quot;Update intro&quot;</code>. Which version of the file goes into the commit?</p>","options":[{"text":"The version you saved most recently.","why":"<code dir=\"ltr\">git commit</code> records the index, not your files on disk. The second edit was never staged."},{"text":"Both versions, as two separate commits.","why":"One <code dir=\"ltr\">git commit</code> always makes one commit. Git doesn’t split edits by when you saved them."},{"text":"The version as it was when you ran <code dir=\"ltr\">git add</code>.","why":"Correct. <code dir=\"ltr\">git add</code> copied that version into the index, and the commit records the index. The later edit is still unstaged."},{"text":"Neither; Git refuses to commit a file that changed after staging.","why":"Git allows it and shows the file as both staged and modified. That’s normal while you build a commit."}],"answer":2},{"q":"<p><code dir=\"ltr\">git status -s</code> shows:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>A  contact.html\n?? notes.txt</code></pre></div>\n<p>What does <code dir=\"ltr\">git commit -m &quot;Add contact page&quot;</code> record?</p>\n","options":[{"text":"Only <code dir=\"ltr\">contact.html</code>.","why":"Correct. <code dir=\"ltr\">A</code> in the left column means it’s staged as a new file; <code dir=\"ltr\">??</code> means <code dir=\"ltr\">notes.txt</code> is untracked and stays out."},{"text":"Both files, because they’re both new.","why":"Being new isn’t enough. Only staged content goes into a commit, and <code dir=\"ltr\">notes.txt</code> was never added."},{"text":"Nothing, because untracked files block a commit.","why":"Untracked files never block commits. Git ignores them unless you stage them."},{"text":"Only <code dir=\"ltr\">notes.txt</code>, because <code dir=\"ltr\">??</code> means it’s ready.","why":"<code dir=\"ltr\">??</code> means Git has never tracked the file. Nothing about it is staged."}],"answer":0},{"q":"<p>Which statement about commit IDs is true?</p>","options":[{"text":"IDs are numbered in order, so a higher ID is always a newer commit.","why":"IDs are hashes, not counters. Their order says nothing about time."},{"text":"You can edit a commit’s message and keep its ID.","why":"The message is part of what’s hashed. Changing it creates a different commit with a new ID."},{"text":"Two people who commit identical files always get the same ID.","why":"The author, time and parent are hashed too, so their commits differ."},{"text":"A commit’s ID depends on its content, author, date, message and parent, so the same change committed twice gets two IDs.","why":"Correct. That’s also why amending, rebasing or reverting always produces new IDs."}],"answer":3},{"q":"<p>Here is the output of <code dir=\"ltr\">git log --oneline --graph</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Text</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"Copy code\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>Copy</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code>*   9d1f0a2 (HEAD -&gt; main) Merge branch 'contact'\n|\\\n| * 6b2c8e1 (contact) Add contact form\n* | 3e7a4d9 Fix header spacing\n|/\n* 1f0c5b8 Add home page</code></pre></div>\n<p>Which commit is <code dir=\"ltr\">HEAD~1</code>?</p>\n","options":[{"text":"<code dir=\"ltr\">6b2c8e1</code>, because it’s the most recent commit before the merge.","why":"<code dir=\"ltr\">~</code> follows the first parent, which for a merge is the branch you were on (<code dir=\"ltr\">main</code>), not the merged branch."},{"text":"<code dir=\"ltr\">3e7a4d9</code>, the merge’s first parent.","why":"Correct. You were on <code dir=\"ltr\">main</code> when you merged, so <code dir=\"ltr\">main</code>’s previous tip is the first parent. <code dir=\"ltr\">HEAD^2</code> would be <code dir=\"ltr\">6b2c8e1</code>."},{"text":"<code dir=\"ltr\">1f0c5b8</code>, because it’s where the two lines meet.","why":"That’s the merge base, two steps back. <code dir=\"ltr\">HEAD~1</code> is one step."},{"text":"None; <code dir=\"ltr\">HEAD~1</code> is an error on a merge commit.","why":"It works fine. Git always follows the first parent for <code dir=\"ltr\">~</code>."}],"answer":1},{"q":"<p>You want to review exactly what your next commit will contain before running <code dir=\"ltr\">git commit</code>. Which command shows it?</p>","options":[{"text":"<code dir=\"ltr\">git diff --staged</code>","why":"Correct. It compares the index with the last commit, which is precisely the change the next commit records."},{"text":"<code dir=\"ltr\">git diff</code>","why":"That shows changes you have <em>not</em> staged yet, which won’t be in the commit."},{"text":"<code dir=\"ltr\">git log -p</code>","why":"That shows past commits and their diffs, not what’s about to be committed."},{"text":"<code dir=\"ltr\">git show HEAD</code>","why":"That shows the last commit you already made."}],"answer":0}],"s-git-2":[{"q":"<p>On <code dir=\"ltr\">main</code>, you run <code dir=\"ltr\">git switch -c hero-image</code>, edit <code dir=\"ltr\">index.html</code> without committing, then run <code dir=\"ltr\">git switch main</code>. Both branches point at the same commit. What happens to your edit?</p>","options":[{"text":"It’s lost, because switching resets the working tree.","why":"Switching keeps uncommitted changes whenever it can. It refuses rather than lose them."},{"text":"It comes with you to <code dir=\"ltr\">main</code> as an uncommitted change.","why":"Correct. Both branches have the same <code dir=\"ltr\">index.html</code>, so nothing needs overwriting and the edit carries over."},{"text":"Git always refuses to switch while you have uncommitted changes.","why":"It only refuses when the switch would overwrite your changes. Here it wouldn’t."},{"text":"It’s committed to <code dir=\"ltr\">hero-image</code> automatically before the switch.","why":"Git never commits for you. Uncommitted work stays uncommitted until you commit it."}],"answer":1},{"q":"<p><code dir=\"ltr\">git branch -d old-layout</code> fails with <code dir=\"ltr\">error: the branch 'old-layout' is not fully merged</code>. What does that mean?</p>","options":[{"text":"You’re currently on <code dir=\"ltr\">old-layout</code>, so it can’t be deleted.","why":"That’s a different error (you can’t delete the branch you’re on). This one is about unmerged commits."},{"text":"The branch doesn’t exist locally.","why":"A missing branch gives a ‘not found’ error, not ‘not fully merged’."},{"text":"GitHub is unreachable, so Git can’t check the branch.","why":"<code dir=\"ltr\">git branch -d</code> works entirely locally and never contacts a remote."},{"text":"Some of its commits aren’t merged into your current branch; merge them, or use <code dir=\"ltr\">-D</code> if you’re sure they’re unwanted.","why":"Correct. <code dir=\"ltr\">-d</code> protects unmerged work. <code dir=\"ltr\">-D</code> deletes anyway, and the reflog can still rescue it for a while."}],"answer":3},{"q":"<p>You’re three commits into <code dir=\"ltr\">git rebase main</code> on your branch when a conflict makes you realise you’d rather merge. How do you return to exactly where you were before the rebase?</p>","options":[{"text":"<code dir=\"ltr\">git merge --abort</code>","why":"There’s no merge in progress. Each operation has its own abort."},{"text":"<code dir=\"ltr\">git reset --hard main</code>","why":"That points your branch at <code dir=\"ltr\">main</code>, dropping your branch’s commits from it. Recoverable via the reflog, but the opposite of what you want."},{"text":"<code dir=\"ltr\">git rebase --abort</code>","why":"Correct. It stops the rebase and puts the branch back on its original commits."},{"text":"<code dir=\"ltr\">git rebase --skip</code>","why":"That drops the conflicting commit and carries on rebasing, so you’d lose work and still be rebasing."}],"answer":2},{"q":"<p>You and a teammate both push to the shared <code dir=\"ltr\">redesign</code> branch on GitHub. It’s fallen behind <code dir=\"ltr\">main</code>. How should you bring it up to date?</p>","options":[{"text":"Merge <code dir=\"ltr\">main</code> into <code dir=\"ltr\">redesign</code> and push.","why":"Correct. A merge adds a commit without rewriting anything your teammate already has."},{"text":"Rebase <code dir=\"ltr\">redesign</code> onto <code dir=\"ltr\">main</code> and <code dir=\"ltr\">git push --force</code>.","why":"That rewrites commits your teammate has built on, which is exactly what the golden rule forbids."},{"text":"Delete <code dir=\"ltr\">redesign</code> and recreate it from <code dir=\"ltr\">main</code>.","why":"That throws away the branch’s work instead of updating it."},{"text":"Run <code dir=\"ltr\">git reset --hard main</code> on <code dir=\"ltr\">redesign</code>.","why":"That discards the branch’s commits from the branch. Nothing is integrated."}],"answer":0},{"q":"<p>During a merge, <code dir=\"ltr\">styles.css</code> conflicts, and you know the incoming branch’s version is right for the whole file. What’s the quickest correct resolution?</p>","options":[{"text":"<code dir=\"ltr\">git restore --ours styles.css</code>, then <code dir=\"ltr\">git add styles.css</code>","why":"<code dir=\"ltr\">--ours</code> keeps your current branch’s version, the opposite of what you want."},{"text":"<code dir=\"ltr\">git merge --abort</code>","why":"That cancels the whole merge rather than resolving it."},{"text":"Delete <code dir=\"ltr\">styles.css</code> and run <code dir=\"ltr\">git commit</code>.","why":"That commits the file’s deletion, breaking the site."},{"text":"<code dir=\"ltr\">git restore --theirs styles.css</code>, then <code dir=\"ltr\">git add styles.css</code> and <code dir=\"ltr\">git commit</code>","why":"Correct. <code dir=\"ltr\">--theirs</code> takes the incoming branch’s version of the conflicted file; staging marks it resolved."}],"answer":3}],"s-git-3":[{"q":"<p><code dir=\"ltr\">git status</code> says <code dir=\"ltr\">Your branch is up to date with 'origin/main'</code>, but GitHub shows a commit on <code dir=\"ltr\">main</code> you don’t have. Why?</p>","options":[{"text":"GitHub’s page is cached and the commit isn’t really there.","why":"GitHub’s page is accurate. Your repository’s information is the stale one."},{"text":"<code dir=\"ltr\">git status</code> ignores commits older than a day.","why":"There’s no such cut-off. Status compares against whatever <code dir=\"ltr\">origin/main</code> currently records."},{"text":"The commit was pushed to a different remote.","why":"It’s on <code dir=\"ltr\">origin</code>’s <code dir=\"ltr\">main</code>, as you can see on GitHub. The issue is when you last asked."},{"text":"Status compares with your last-known <code dir=\"ltr\">origin/main</code>, which only updates when you fetch; run <code dir=\"ltr\">git fetch</code> and check again.","why":"Correct. Git doesn’t contact GitHub for <code dir=\"ltr\">git status</code>. After a fetch, it will report that you’re behind."}],"answer":3},{"q":"<p>You push a new branch with <code dir=\"ltr\">git push</code> and get <code dir=\"ltr\">fatal: The current branch contact-form has no upstream branch.</code> What’s going on?</p>","options":[{"text":"The remote <code dir=\"ltr\">origin</code> hasn’t been added yet.","why":"With no remote at all, Git would complain about the missing repository, not the missing upstream."},{"text":"The branch has never been pushed, so it has no upstream; run <code dir=\"ltr\">git push -u origin contact-form</code>.","why":"Correct. <code dir=\"ltr\">-u</code> pushes and records the upstream, so later bare <code dir=\"ltr\">git push</code> and <code dir=\"ltr\">git pull</code> work."},{"text":"Your credentials have expired.","why":"Authentication errors mention access or authentication. This one is about tracking."},{"text":"You need to <code dir=\"ltr\">git pull</code> before pushing a new branch.","why":"There’s nothing to pull: the branch doesn’t exist on GitHub yet."}],"answer":1},{"q":"<p>Your team wants <code dir=\"ltr\">main</code> to get exactly one commit per pull request, titled after the pull request. Which merge method fits?</p>","options":[{"text":"Squash and merge","why":"Correct. All the branch’s commits become a single new commit on <code dir=\"ltr\">main</code>."},{"text":"Create a merge commit","why":"That keeps every branch commit plus a merge commit, so <code dir=\"ltr\">main</code> gets several commits per pull request."},{"text":"Rebase and merge","why":"That replays every commit individually onto <code dir=\"ltr\">main</code>, with no single summary commit."},{"text":"Close the pull request and push the changes directly","why":"That skips review and, with protection rules, is blocked anyway."}],"answer":0},{"q":"<p>You cloned your fork of a project. <code dir=\"ltr\">git remote -v</code> lists only <code dir=\"ltr\">origin</code>, pointing at your fork. How do you get the original project’s latest commits?</p>","options":[{"text":"<code dir=\"ltr\">git pull origin main</code>","why":"Your fork doesn’t have the original’s newest commits until you sync it, so this pulls stale history."},{"text":"<code dir=\"ltr\">git clone</code> the original into the same folder.","why":"Clone creates a new repository; it can’t merge into an existing one."},{"text":"<code dir=\"ltr\">git remote add upstream &lt;original-url&gt;</code>, then <code dir=\"ltr\">git fetch upstream</code> and merge <code dir=\"ltr\">upstream/main</code>.","why":"Correct. A second remote for the original lets you fetch it directly while still pushing to your fork."},{"text":"Delete your fork and fork again.","why":"That works once, at the cost of your branches and any open pull requests. A remote does it every time."}],"answer":2},{"q":"<p>Your pull request says <code dir=\"ltr\">Fixes #31</code> and was merged into the <code dir=\"ltr\">develop</code> branch, but issue 31 is still open. The repository’s default branch is <code dir=\"ltr\">main</code>. Why?</p>","options":[{"text":"<code dir=\"ltr\">Fixes</code> isn’t a recognised keyword; only <code dir=\"ltr\">Closes</code> works.","why":"<code dir=\"ltr\">fixes</code>, <code dir=\"ltr\">closes</code> and <code dir=\"ltr\">resolves</code> all work, along with their variants."},{"text":"Closing keywords take effect only when the pull request is merged into the default branch.","why":"Correct. The issue will close when the change reaches <code dir=\"ltr\">main</code>, or you can close it by hand."},{"text":"The keyword must be in the pull request title, not the description.","why":"The description is the normal place for closing keywords."},{"text":"Issues can only be closed by the person who opened them.","why":"Anyone with write access can close an issue, and merging can close it automatically."}],"answer":1}],"s-git-4":[{"q":"<p>You made three local commits on your branch: <code dir=\"ltr\">wip 1</code>, <code dir=\"ltr\">wip 2</code>, <code dir=\"ltr\">wip 3</code>. None are pushed. You want one clean commit instead. What’s the most direct way?</p>","options":[{"text":"<code dir=\"ltr\">git reset --soft HEAD~3</code>, then <code dir=\"ltr\">git commit -m &quot;Add contact validation&quot;</code>","why":"Correct. The branch moves back three commits while all their changes stay staged, ready to commit once."},{"text":"<code dir=\"ltr\">git revert HEAD~3..HEAD</code>","why":"That adds three more commits undoing the first three, the opposite of what you want."},{"text":"<code dir=\"ltr\">git reset --hard HEAD~3</code>, then commit","why":"<code dir=\"ltr\">--hard</code> discards the changes too, so there’d be nothing to commit."},{"text":"<code dir=\"ltr\">git commit --amend</code> three times","why":"Amend only replaces the last commit each time; it doesn’t combine earlier ones."}],"answer":0},{"q":"<p><code dir=\"ltr\">git stash list</code> shows three entries. You want to apply the middle one, <code dir=\"ltr\">stash@{1}</code>, and keep it in the list in case you need it again. Which command?</p>","options":[{"text":"<code dir=\"ltr\">git stash pop stash@{1}</code>","why":"Pop applies the stash and then deletes it, so it wouldn’t stay in the list."},{"text":"<code dir=\"ltr\">git stash show stash@{1}</code>","why":"That shows what’s in the stash without applying anything."},{"text":"<code dir=\"ltr\">git stash apply stash@{1}</code>","why":"Correct. <code dir=\"ltr\">apply</code> restores the changes and leaves the stash entry in place."},{"text":"<code dir=\"ltr\">git stash push stash@{1}</code>","why":"<code dir=\"ltr\">push</code> creates a new stash from your current changes; it doesn’t apply one."}],"answer":2},{"q":"<p>Which <code dir=\"ltr\">.gitignore</code> ignores every <code dir=\"ltr\">.log</code> file in the project except <code dir=\"ltr\">logs/keep.log</code>?</p>","options":[{"text":"<code dir=\"ltr\">logs/</code> on one line, then <code dir=\"ltr\">!logs/keep.log</code>","why":"Once the <code dir=\"ltr\">logs/</code> folder is ignored, Git never looks inside it, so the <code dir=\"ltr\">!</code> line can’t re-include the file."},{"text":"<code dir=\"ltr\">*.log</code> on one line, then <code dir=\"ltr\">!logs/keep.log</code>","why":"Correct. Only files are excluded, the folder isn’t, so the later <code dir=\"ltr\">!</code> line can re-include that one file."},{"text":"<code dir=\"ltr\">!logs/keep.log</code> on one line, then <code dir=\"ltr\">*.log</code>","why":"Later lines win. <code dir=\"ltr\">*.log</code> comes last and ignores <code dir=\"ltr\">keep.log</code> again."},{"text":"<code dir=\"ltr\">*.log # except logs/keep.log</code>","why":"<code dir=\"ltr\">#</code> only starts a comment at the beginning of a line; this pattern matches a file with that whole name."}],"answer":1},{"q":"<p>Your pull request shows a red cross next to <code dir=\"ltr\">CI / check</code>. What should you do?</p>","options":[{"text":"Click Re-run until it turns green.","why":"If the check fails for a real reason, re-running gives the same result. Re-run only for genuinely flaky failures."},{"text":"Ask a repository admin to bypass the rule and merge.","why":"Bypassing defeats the check. Find out why it fails first."},{"text":"Close the pull request and open a new one.","why":"A new pull request runs the same check on the same code and fails the same way."},{"text":"Open Details, read the failing step’s log, reproduce it locally with <code dir=\"ltr\">npm test</code>, then fix, commit and push to the same branch.","why":"Correct. The new push reruns the workflow on the updated pull request."}],"answer":3},{"q":"<p>The commit currently deployed should be published as version 1.2.0 on GitHub. Which commands do it?</p>","options":[{"text":"<code dir=\"ltr\">git branch v1.2.0</code>, then <code dir=\"ltr\">git push origin v1.2.0</code>","why":"A branch moves as you commit, so it’s the wrong tool for marking a fixed version."},{"text":"<code dir=\"ltr\">git tag v1.2.0</code>, then <code dir=\"ltr\">git push</code>","why":"This creates a lightweight tag and then doesn’t push it, because a plain push doesn’t send tags."},{"text":"<code dir=\"ltr\">git tag -a v1.2.0 -m &quot;Release 1.2.0&quot;</code>, then <code dir=\"ltr\">git push origin v1.2.0</code>","why":"Correct. An annotated tag records who marked the release and why, and the tag must be pushed explicitly."},{"text":"<code dir=\"ltr\">git commit --tag v1.2.0</code>","why":"<code dir=\"ltr\">git commit</code> has no <code dir=\"ltr\">--tag</code> option. Tags are created with <code dir=\"ltr\">git tag</code>."}],"answer":2}]},"final":[{"q":"<p>Which description of a Git branch is accurate?</p>","options":[{"text":"A full copy of the project’s files stored in its own folder.","why":"That’s how some older systems worked. In Git, creating a branch copies nothing."},{"text":"A named, movable pointer to one commit; the history comes from following parents.","why":"Correct. That’s why branches are cheap to make, switch and delete."},{"text":"A folder inside <code dir=\"ltr\">.git</code> holding every commit made on that branch.","why":"Commits aren’t filed by branch. A branch file holds a single commit ID."},{"text":"The copy of the repository that lives on GitHub.","why":"That’s a remote. Branches exist both locally and on remotes."}],"answer":1},{"q":"<p>You made two commits on <code dir=\"ltr\">main</code> that were meant for a new branch. Nothing is pushed yet. What’s the cleanest fix?</p>","options":[{"text":"<code dir=\"ltr\">git revert HEAD~2..HEAD</code>, then redo the work on a branch.","why":"Reverting adds undo commits to <code dir=\"ltr\">main</code> for work nobody else has seen, and you’d redo the work by hand."},{"text":"<code dir=\"ltr\">git switch -c contact-form</code> and carry on.","why":"The new branch has the commits, but <code dir=\"ltr\">main</code> still has them too."},{"text":"<code dir=\"ltr\">git push</code>, then fix it on GitHub.","why":"That publishes the mistake first, which turns an easy local fix into a shared-history problem."},{"text":"<code dir=\"ltr\">git branch contact-form</code>, <code dir=\"ltr\">git reset --hard origin/main</code>, then <code dir=\"ltr\">git switch contact-form</code>.","why":"Correct. The new branch keeps the commits, and <code dir=\"ltr\">main</code> goes back to match GitHub."}],"answer":3},{"q":"<p>Which command lists the commits on <code dir=\"ltr\">feature</code> that are not on <code dir=\"ltr\">main</code>?</p>","options":[{"text":"<code dir=\"ltr\">git log --oneline main..feature</code>","why":"Correct. <code dir=\"ltr\">A..B</code> means commits reachable from B but not from A."},{"text":"<code dir=\"ltr\">git log --oneline feature..main</code>","why":"That’s the reverse: commits on <code dir=\"ltr\">main</code> that <code dir=\"ltr\">feature</code> lacks."},{"text":"<code dir=\"ltr\">git diff main feature</code>","why":"That compares two snapshots line by line. It doesn’t list commits."},{"text":"<code dir=\"ltr\">git log --oneline --all</code>","why":"That lists every commit on every branch, without separating them."}],"answer":0},{"q":"<p>With <code dir=\"ltr\">pull.rebase</code> set to <code dir=\"ltr\">true</code>, <code dir=\"ltr\">git pull</code> stops with a conflict in <code dir=\"ltr\">index.html</code>. You’ve fixed the file. What finishes the job?</p>","options":[{"text":"<code dir=\"ltr\">git add index.html</code>, then <code dir=\"ltr\">git merge --continue</code>","why":"No merge is in progress. With <code dir=\"ltr\">pull.rebase true</code>, the pull is rebasing."},{"text":"<code dir=\"ltr\">git commit -am &quot;Fix conflict&quot;</code>","why":"During a rebase, Git makes the commits itself. A manual commit adds an extra one."},{"text":"<code dir=\"ltr\">git add index.html</code>, then <code dir=\"ltr\">git rebase --continue</code>","why":"Correct. Stage the resolution and let the rebase replay your remaining commits."},{"text":"Run <code dir=\"ltr\">git pull</code> again.","why":"A rebase is already in progress, so Git won’t start another operation until you finish or abort it."}],"answer":2},{"q":"<p>You force-deleted <code dir=\"ltr\">experiment</code> with <code dir=\"ltr\">git branch -D</code> and then remembered it had a commit you need. How do you get it back?</p>","options":[{"text":"Restore it from the Trash; Git moves deleted branches there.","why":"Git doesn’t use your system’s Trash. The commit is still inside <code dir=\"ltr\">.git</code>."},{"text":"Run <code dir=\"ltr\">git revert experiment</code>.","why":"The branch name no longer exists, and revert creates undo commits anyway."},{"text":"Find the commit in <code dir=\"ltr\">git reflog</code>, then <code dir=\"ltr\">git switch -c experiment &lt;commit-id&gt;</code>.","why":"Correct. Deleting a branch removes a pointer; the reflog remembers where HEAD was, so you can point a new branch at it."},{"text":"It’s gone for good; <code dir=\"ltr\">-D</code> deletes commits permanently.","why":"<code dir=\"ltr\">-D</code> deletes only the branch label. Unreachable commits stay recoverable for weeks."}],"answer":2},{"q":"<p>Your team agrees that nobody pushes to <code dir=\"ltr\">main</code> directly and every pull request must pass CI. What enforces that?</p>","options":[{"text":"A branch ruleset on <code dir=\"ltr\">main</code> with Require a pull request and Require status checks to pass.","why":"Correct. GitHub then rejects direct pushes and keeps merge disabled until the required check is green."},{"text":"A note in CONTRIBUTING.md.","why":"Documentation explains the rule but can’t stop anyone from breaking it."},{"text":"A workflow that reverts any direct push to <code dir=\"ltr\">main</code>.","why":"That reacts after the damage, and adds noise to history. Rules prevent it up front."},{"text":"Adding <code dir=\"ltr\">main</code> to <code dir=\"ltr\">.gitignore</code>.","why":"<code dir=\"ltr\">.gitignore</code> controls which files Git tracks. It has nothing to do with branches or pushes."}],"answer":0},{"q":"<p>Which of these is safe to do on a branch your teammates have already pulled?</p>","options":[{"text":"<code dir=\"ltr\">git commit --amend</code> on the latest commit, then force-push.","why":"Amending replaces a commit they already have, so their history and yours no longer match."},{"text":"<code dir=\"ltr\">git rebase -i</code> to squash old commits, then force-push.","why":"Rebasing rewrites shared commits, which breaks the golden rule."},{"text":"<code dir=\"ltr\">git reset --hard HEAD~2</code>, then force-push.","why":"That deletes commits from a branch others have built on."},{"text":"<code dir=\"ltr\">git revert &lt;commit&gt;</code> and a normal push.","why":"Correct. Revert adds a new commit and rewrites nothing, so teammates just pull it."}],"answer":3},{"q":"<p><code dir=\"ltr\">styles.css</code> has two unrelated changes: a colour fix and the start of a new layout. You want to commit only the colour fix. What do you use?</p>","options":[{"text":"<code dir=\"ltr\">git commit -a</code>","why":"That commits every tracked change, including the unfinished layout."},{"text":"<code dir=\"ltr\">git add -p styles.css</code>, staging only the colour hunk","why":"Correct. Patch mode lets you stage individual hunks, so the commit contains just the fix."},{"text":"<code dir=\"ltr\">git stash</code>, then commit","why":"Stashing removes both changes, leaving nothing to commit."},{"text":"<code dir=\"ltr\">git restore styles.css</code>, then commit","why":"That discards both changes from the file."}],"answer":1},{"q":"<p>Which statement about SSH authentication with GitHub is true?</p>","options":[{"text":"You paste your private key into GitHub so it can verify you.","why":"The private key must never leave your machine. GitHub only needs the public key."},{"text":"SSH keys expire every 30 days and must be regenerated.","why":"GitHub SSH keys have no expiry date (GitHub only removes a key after a year without use). You delete them when a device is retired."},{"text":"Once SSH is set up, every remote uses it automatically.","why":"The remote URL decides. <code dir=\"ltr\">https://</code> URLs keep using HTTPS until you change them."},{"text":"You add the <code dir=\"ltr\">.pub</code> public key to GitHub, and the private key stays on your machine.","why":"Correct. GitHub checks that you hold the private key matching the public key on your account."}],"answer":3},{"q":"<p><code dir=\"ltr\">main</code> hasn’t moved since you created <code dir=\"ltr\">footer</code>, but you want <code dir=\"ltr\">main</code>’s history to show the footer work as one grouped feature. Which command?</p>","options":[{"text":"<code dir=\"ltr\">git merge footer</code>","why":"With <code dir=\"ltr\">main</code> unmoved, this fast-forwards, so there’s no merge commit and no grouping."},{"text":"<code dir=\"ltr\">git merge --no-ff footer</code>","why":"Correct. It forces a merge commit even when a fast-forward was possible."},{"text":"<code dir=\"ltr\">git merge --ff-only footer</code>","why":"That allows only a fast-forward, the opposite of what you want."},{"text":"<code dir=\"ltr\">git rebase footer</code>","why":"Rebasing <code dir=\"ltr\">main</code> onto <code dir=\"ltr\">footer</code> gives you a straight line, with no grouping either."}],"answer":1},{"q":"<p>In a fork workflow, where does your feature branch go before you open the pull request?</p>","options":[{"text":"Directly to the original repository (<code dir=\"ltr\">upstream</code>).","why":"Without write access, that push is rejected. That’s why the fork exists."},{"text":"Nowhere; GitHub reads branches from your laptop.","why":"GitHub can only see what’s been pushed to a repository on GitHub."},{"text":"To your fork (<code dir=\"ltr\">origin</code>), then the pull request goes from your fork’s branch to the original’s <code dir=\"ltr\">main</code>.","why":"Correct. You push where you have write access, and propose the change back to the original."},{"text":"To your fork’s <code dir=\"ltr\">main</code> branch.","why":"Keeping <code dir=\"ltr\">main</code> as a mirror of upstream and using a separate branch per contribution avoids messy pull requests."}],"answer":2},{"q":"<p>A workflow at <code dir=\"ltr\">.github/workflow/ci.yml</code> never runs on pull requests, and the Actions tab shows nothing. What’s the most likely cause?</p>","options":[{"text":"The folder must be named <code dir=\"ltr\">.github/workflows</code> (plural).","why":"Correct. GitHub only reads workflow files from <code dir=\"ltr\">.github/workflows/</code>."},{"text":"The file must be called <code dir=\"ltr\">main.yml</code>.","why":"Workflow files can have any name ending in <code dir=\"ltr\">.yml</code> or <code dir=\"ltr\">.yaml</code>."},{"text":"Actions only run on private repositories.","why":"Actions run on public and private repositories alike."},{"text":"Workflows only run after a ruleset requires them.","why":"Rulesets can require a check, but workflows run on their own triggers regardless."}],"answer":0}],"glossary":[{"id":"version-control","term":"Version control","definition":"A system that records snapshots of a project over time, so you can see what changed, when and why, return to earlier versions, and combine work from several people.","lesson":"l-git-1-1"},{"id":"repository","term":"Repository","definition":"A project’s complete history and settings, stored in the hidden .git folder; it holds every commit, branch and tag, and is created with git init or git clone.","lesson":"l-git-1-2"},{"id":"commit","term":"Commit","definition":"A recorded snapshot of every tracked file, with an author, date, message and a pointer to its parent commit. Its ID is a hash of all of that, so it never changes.","lesson":"l-git-1-1"},{"id":"working-tree","term":"Working tree","definition":"The project files on disk that you open and edit. Git compares them with the index and the last commit to report what has changed.","lesson":"l-git-1-3"},{"id":"index","term":"Index (staging area)","definition":"The next commit being assembled. git add copies a file’s current content into it, git commit turns it into a commit, and git restore --staged takes content back out.","lesson":"l-git-1-3"},{"id":"untracked-file","term":"Untracked file","definition":"A file in the working tree that Git has never recorded and that isn’t staged. It stays out of commits until you git add it, and .gitignore can hide it.","lesson":"l-git-1-2"},{"id":"dag","term":"Commit graph (DAG)","definition":"Git history as a directed acyclic graph: each commit points to its parent or parents, and following those links backwards from any commit gives its history.","lesson":"l-git-1-4"},{"id":"merge-commit","term":"Merge commit","definition":"A commit with two parents, created when Git combines two branches that have both moved on. Its snapshot contains the work from both lines of history.","lesson":"l-git-1-4"},{"id":"branch","term":"Branch","definition":"A named, movable pointer to one commit. Committing while on a branch moves it forward to the new commit; creating one copies no files.","lesson":"l-git-2-1"},{"id":"head","term":"HEAD","definition":"Git’s pointer to where you are. It usually names the current branch, which names a commit; HEAD~1 means the commit before the one you’re on.","lesson":"l-git-2-1"},{"id":"detached-head","term":"Detached HEAD","definition":"The state where HEAD points straight at a commit instead of a branch. New commits made there belong to no branch until you create one with git switch -c.","lesson":"l-git-2-1"},{"id":"fast-forward","term":"Fast-forward","definition":"A merge where the current branch hasn’t moved since the other branch started, so Git simply slides the pointer forward and creates no merge commit.","lesson":"l-git-2-2"},{"id":"merge-base","term":"Merge base","definition":"The most recent commit two branches share. Git compares each branch tip with it during a three-way merge to decide which changes to take.","lesson":"l-git-2-2"},{"id":"merge-conflict","term":"Merge conflict","definition":"What happens when both branches changed the same lines since their merge base. Git writes both versions between markers and waits for you to edit, git add and continue.","lesson":"l-git-2-3"},{"id":"rebase","term":"Rebase","definition":"Replaying a branch’s commits on top of another commit, producing new commits with new IDs and a linear history. Safe only for commits nobody else has built on.","lesson":"l-git-2-4"},{"id":"force-with-lease","term":"git push --force-with-lease","definition":"A force-push that only overwrites the remote branch if it still points where you last saw it, so you won’t silently erase commits someone else pushed since your last fetch.","lesson":"l-git-2-4"},{"id":"remote","term":"Remote","definition":"A named URL for another copy of the repository, usually on GitHub. origin is the conventional name for the one you cloned from or push to.","lesson":"l-git-3-1"},{"id":"remote-tracking-branch","term":"Remote-tracking branch","definition":"A local, read-only record such as origin/main of where a branch was on a remote at your last fetch, pull or push. It moves only when you talk to the remote.","lesson":"l-git-3-1"},{"id":"upstream-branch","term":"Upstream branch","definition":"The remote branch a local branch tracks, set with git push -u. It lets plain git push and git pull work and lets git status report ahead and behind counts.","lesson":"l-git-3-1"},{"id":"ssh-key","term":"SSH key pair","definition":"Two linked keys used to prove who you are to GitHub: the private key stays on your machine, and the .pub public key is added to your GitHub account.","lesson":"l-git-3-2"},{"id":"pull-request","term":"Pull request","definition":"A GitHub proposal to merge one branch into another, where reviewers comment, automated checks run, and the change is finally merged. New pushes to the branch update it.","lesson":"l-git-3-3"},{"id":"fork","term":"Fork","definition":"Your own copy of someone else’s repository on GitHub. You push branches to it and open pull requests back to the original, conventionally called upstream.","lesson":"l-git-3-4"},{"id":"revert","term":"git revert","definition":"A command that creates a new commit applying the exact opposite of an earlier commit. It undoes changes without rewriting history, so it’s safe on shared branches.","lesson":"l-git-4-1"},{"id":"reflog","term":"Reflog","definition":"A local log of every position HEAD has had, such as commits, resets, rebases and switches. It lets you find and restore commits that no branch points to any more.","lesson":"l-git-4-1"},{"id":"stash","term":"Stash","definition":"A place to park uncommitted changes and get a clean working tree. git stash push saves them, git stash pop brings them back; add -u to include untracked files.","lesson":"l-git-4-2"},{"id":"gitignore","term":".gitignore","definition":"A file listing patterns of untracked files Git should never track, such as node_modules/, build output and .env. It doesn’t affect files that are already tracked.","lesson":"l-git-4-2"},{"id":"conventional-commits","term":"Conventional Commits","definition":"A commit message format, type(optional scope): description, using types like feat, fix and docs, so tools can generate changelogs and semantic version numbers.","lesson":"l-git-4-3"},{"id":"annotated-tag","term":"Annotated tag","definition":"A permanent, named marker on a commit that also stores the tagger, date and a message. Created with git tag -a, it’s the usual way to mark a release.","lesson":"l-git-4-3"},{"id":"github-actions-workflow","term":"GitHub Actions workflow","definition":"A YAML file in .github/workflows/ that runs jobs on GitHub’s machines when events like pull_request happen. Each job reports a status check on the pull request.","lesson":"l-git-4-4"},{"id":"ruleset","term":"Ruleset","definition":"A named set of GitHub rules for branches or tags, such as requiring a pull request, requiring status checks to pass and blocking force pushes on main.","lesson":"l-git-4-4"}]}