- Which workflow accomplishes this without first committing the changes on
main? Answer: Run git switch -c feature/logging, stage the changes, and commit on the new branch.
When working with Git, questions like this test your understanding of how branching interacts with your working tree — specifically, that uncommitted changes travel with you when you switch branches, as long as there's no conflict.
The key insight here is that git switch -c feature/logging creates a new branch and switches to it in one step, bringing your unstaged changes along for the ride. Once there, you stage and commit, so the new commit lands on feature/logging — never on main. This makes B the correct answer: it achieves exactly what the scenario requires with a clean, minimal workflow.
A is tempting but subtly wrong. Running git branch feature/logging creates the branch but does not switch to it. If you then stage and commit without switching, the commit goes onto main — the opposite of what you want. The branch exists, but it just points to the same old commit.
C violates the constraint directly. Committing on main first means main advances to a new commit, which the scenario explicitly forbids. Creating the branch afterward doesn't undo that.
D is unnecessarily convoluted and actually broken. Stashing saves your changes, but then committing without restoring the stash means you commit nothing meaningful. You've also added extra steps that solve a problem that doesn't exist — Git lets you carry uncommitted changes across branch switches freely.
As a study tip, remember: git switch -c <branch> is your one-stop command for "I want to start fresh work on a new branch right now." Uncommitted changes follow you automatically — no stashing needed.
- Which commit message most meaningfully communicates the purpose of this change?
Answer: Fix cache lookup to reject expired entries instead of returning stale values
When evaluating commit messages in software development, ask yourself: does this message tell a future developer why the change was made and what problem it solves, without reading the code itself? A great commit message is a form of documentation — it should convey intent, not just acknowledge that something changed.
Option B accomplishes exactly this. It identifies the specific component (cache lookup), names the bug being fixed (rejecting expired entries), and explains the consequence being prevented (returning stale values). A developer browsing git history immediately understands the motivation and scope of the change — no code-reading required.
Option A fails because it only names the files that were modified. File names tell you where the change happened, not why. Any commit that touches Cache.cpp could carry this message — it's completely generic and useless for understanding history.
Option C commits the classic sin of vagueness. Phrases like "several improvements" and "requested during development" are noise — they could describe virtually any commit ever made. This message communicates almost nothing actionable or searchable.
Option D is slightly more specific than A but still falls short. It describes the change in purely mechanical terms ("conditional from previous to new implementation") without explaining what the conditional does or why it was changed. It's the difference between saying "we moved furniture" versus "we rearranged the office so the team can collaborate more easily."
As a study tip: when choosing commit messages on exam questions, eliminate any option that could apply to any commit (vague language, file names only, or purely mechanical descriptions). The best message is always the one that answers "why" and "what problem does this solve?"
- Which sequence most directly adds the omitted file to that existing commit?
Answer: Stage ParserTests.cpp, then run git commit --amend --no-edit to replace the local commit.
When you need to fold a forgotten file into your most recent local commit without changing its message, the key concept is amending commits. Git's --amend flag rewrites the last commit by combining it with whatever is currently staged — so the order of operations matters critically.
The correct approach (C) mirrors exactly how amending is designed to work: you first stage ParserTests.cpp with git add, then run git commit --amend --no-edit. Git bundles the newly staged file together with the previous commit's snapshot and produces a single, clean replacement commit. The --no-edit flag preserves the original message, which is exactly what the scenario calls for.
Choice A is tempting but creates a brand-new second commit instead of modifying the existing one. You'd end up with two commits — the original missing the file, and a follow-up adding it — which is messy history for something that was always meant to be one unit of work.
Choice B reverses the required order. Running git commit --amend --no-edit before staging the file means the amendment fires with nothing new staged, effectively just rewriting the commit timestamp without adding ParserTests.cpp. The file would still be missing from the commit.
Choice D is destructive overkill. git reset --hard discards all uncommitted changes entirely, and it doesn't isolate just the omitted file — you'd risk losing other work and would have to rebuild the commit from scratch unnecessarily.
As a study tip, remember the amendment mantra: stage first, amend second. Any question asking you to modify a recent unpushed commit should immediately trigger this two-step sequence in that exact order.
- What is the most appropriate next step for producing the intended commit?
Answer: Fix the formatting in the offending file, stage the corrected content, and retry the commit with the intended message.
When working with Git hooks, it helps to understand what a pre-commit hook actually does: it runs a script before finalizing a commit, and if that script exits with an error, Git halts the entire process. The commit is not created, and nothing is automatically fixed for you. Your job is to resolve whatever the hook flagged and try again.
That's exactly why C is correct. When the formatting check rejects your commit, you need to open the offending file, fix the formatting violations manually (or with a formatter tool), stage those changes with git add, and then re-run your original commit command with the same message. This is the standard, intended workflow — hooks exist precisely to enforce quality gates before code lands in history.
Option A describes something Git simply doesn't do. A rejected commit leaves your working tree exactly as you left it; Git never automatically reformats files on your behalf. Retrying the identical command without fixing anything will produce the same rejection every time.
Option B misunderstands how hooks and remotes interact. Pre-commit hooks run locally — the remote never even sees a commit that was blocked before it was created. You cannot "push around" a hook that prevented the commit from existing in the first place.
Option D is a workaround that defeats the purpose of the hook entirely. An empty commit bypasses the staged changes and leaves your actual code changes unattached to that commit, creating a messy, incomplete history without solving the underlying formatting problem.
As a study tip: whenever a question involves a Git hook rejection, ask yourself where the problem lives (local, not remote) and who is responsible for fixing it (you, not Git automatically).
- Which command best provides that review?
Answer: git diff --staged, because it compares the staged content with the current HEAD.
When working with Git, it helps to picture the three-zone model: your working directory, the staging area (index), and the committed history. Questions about reviewing changes before a commit are really asking which command targets the staging area specifically.
git diff --staged (also written as git diff --cached) compares what's in your staging area against HEAD — the last commit. This is precisely the diff that will be recorded when you run git commit, making D the correct choice for reviewing exactly what the next commit will contain.
Choice A has the right tool (git diff) but the wrong description. git diff without flags compares your working directory to the staging area — it shows you unstaged changes, not staged ones. It's the opposite of what the question asks.
Choice B (git log -p -1) shows the diff from the most recent existing commit — changes that were already committed. It looks backward at history, not forward at what you're about to commit. Nothing in the staging area is visible here.
Choice C (git status) is a common trap. It tells you which files have staged or unstaged changes, but it never shows you the actual line-level diffs. You see file names and states, not the content of the edits.
A useful memory trick: think of --staged as "what I've staged for the stage." Whenever an exam question mentions reviewing exact line changes before committing, that's your signal to reach for git diff --staged, because it's the only command that looks directly into the index and compares it against the committed baseline.
- Which workflow best satisfies the team's expectation?
Answer: Use selective staging to commit the timeout fix first, then commit the unrelated formatting separately.
When working with version control, the core principle at stake here is atomic commits — each commit should represent a single, logical change that can be reviewed and reverted independently. When you see a question about committing mixed changes, ask yourself: "Can someone understand, review, or undo this change without affecting unrelated work?"
Selective staging (also called partial staging with git add -p or staging specific hunks) is precisely the tool Git provides for this situation. By staging only the lines related to the timeout fix first, you commit that as one clean, focused change. Then you stage the formatting changes separately and commit those. This gives your team two independently reviewable, safely reversible commits — exactly what the scenario requires. B is correct.
A falls into the trap of convenience over correctness. Bundling both changes into one commit with a dual-purpose message makes it impossible to revert just the timeout fix or just the formatting without undoing both. The message length doesn't solve the underlying problem of mixed concerns.
C is particularly deceptive — an "empty commit" carries no actual code changes, so the timeout fix never actually gets its own commit. The reformatting commit would still contain both sets of changes, making it unfixable from a review perspective.
D sounds clever but is fundamentally broken. Committing the same fully staged file twice doesn't split the changes — the second commit would either be identical to the first or contain nothing new. You cannot separate changes by message alone.
As a study tip: whenever a scenario mentions "independently reversible" or "separately reviewable," that's your signal to think about atomic commits and selective staging.
- Which workflow best prepares an appropriate source-only commit?
Answer: Unstage build/app.exe, add an appropriate ignore rule, stage that rule, and commit the source changes.
When working with Git, questions like this test your understanding of the staging area (index) and how .gitignore interacts with already-tracked or already-staged files. The key insight is that .gitignore only prevents future staging — it does nothing to files already in the index.
The correct workflow is D. First, you unstage build/app.exe using git restore --staged build/app.exe (or git reset HEAD build/app.exe), which removes it from the snapshot-in-progress without deleting it from disk. Then you add an ignore rule (e.g., build/ or build/app.exe) to .gitignore, stage that .gitignore change, and commit only your source files. This produces a clean, source-only commit and ensures the executable is ignored going forward.
A is tempting but wrong — adding a rule to .gitignore does not unstage a file that's already staged. The executable would still appear in your commit because .gitignore has no retroactive effect on the index.
B commits the binary into history first, which is the problem you're trying to avoid. Git does not retroactively scrub committed files; removing them later requires history rewriting, which is painful and disruptive to collaborators.
C deletes the file from disk but leaves it staged. Git would then commit a "deletion" of the file rather than simply omitting it — and it still doesn't add an ignore rule, so future builds would re-stage it.
Study tip: Remember the mantra — *.gitignore ignores the untracked, not the staged.* Whenever an unwanted file is already staged, your first move is always to unstage it explicitly before adding any ignore rules.
- Which files are included in the new commit?
Answer: Only Tokenizer.cpp, because an ordinary commit records the content currently in the staging area.
When working with Git, the most important mental model to carry is the three-area workflow: your working directory, the staging area (index), and the repository. A git commit only packages what lives in the staging area — nothing more, nothing less.
In this scenario, git status tells you everything you need. Tokenizer.cpp appears under Changes to be committed, which means it has been explicitly added to the staging area via git add. That is the only file Git will bundle into the new commit, making A the correct answer.
Here's why each distractor fails: B claims Git automatically includes unstaged modifications to tracked files — it doesn't. README.md was modified but never staged, so it sits in the working directory untouched by the commit. C suggests that untracked files like sample.txt are swept up automatically. They aren't — untracked files are completely invisible to git commit until you explicitly run git add on them. D would be true only if Git recorded a snapshot of your entire working directory, but that's not how Git works; it records only what you've deliberately staged. Confusing "working directory" with "staging area" is one of the most common Git misconceptions you'll encounter.
A useful memory trick: think of the staging area as a shipping box. You decide exactly what goes in it with git add. Running git commit seals and ships only that box — files still on your desk (README.md) or in the corner unopened (sample.txt) stay behind entirely.
- Assuming no hooks reject the operation, what will this command do?
Answer: Commit both modified tracked files, while leaving the new untracked test file outside the commit.
When you see a question involving git commit -am, the key concept being tested is the precise scope of Git's -a flag and how Git distinguishes between tracked and untracked files.
The -a flag tells Git to automatically stage all modifications and deletions to files that are already tracked by the repository, then commit them. In this scenario, Engine.cpp and Config.cpp are both tracked and modified, so -a picks them up and includes them in the commit — no prior git add needed. EngineTests.cpp, however, has never been staged or committed before, meaning Git doesn't track it yet. The -a flag has no power over untracked files; only an explicit git add can bring a new file under Git's awareness. So A is correct: both modified tracked files are committed, and the new file is left untouched.
B is wrong because it overstates what -a does. The flag does not act as a catch-all for every changed path — it specifically ignores untracked files. C is wrong because commit messages are purely descriptive metadata; Git never parses the message to decide which files to include. D is wrong because -a exists precisely to bypass the manual staging step for already-tracked files — it's a convenience shortcut, not something that requires pre-staging.
A helpful mental model: think of -a as "auto-stage my tracked changes." If a file has never introduced itself to Git via git add, -a won't invite it to the commit party.
- Which version of
Parser.cpp is recorded by the commit? Answer: The version staged by git add; the later edits remain as unstaged working-tree changes.
When working with Git, it helps to think of three distinct zones: your working tree (files on disk), the staging area (also called the index), and the commit history. Understanding how git add and git commit interact with these zones is exactly what this question tests.
git add takes a snapshot of the file at that moment and copies it into the staging area. Critically, the staging area does not maintain a live link to the file — it holds a frozen copy. So when you edit Parser.cpp a second time without running git add again, the staging area still holds the first version. When you run git commit, Git packages whatever is currently in the staging area into the new commit — nothing more. That makes A correct: the commit records the version from the first git add, and your second round of edits simply sits in the working tree as unstaged changes.
B is wrong because Git never automatically pulls unstaged changes into a commit. You must explicitly stage changes with git add before they're included. C is wrong because Git doesn't track "rounds of editing" as separate revisions — a commit is a single snapshot of what's in the staging area at commit time. D is wrong because modifying a staged file doesn't remove it from the index; it just creates a divergence between the staged version and the working-tree version, which git status will clearly show you.
A useful mental model: think of git add as pressing "save to staging." Until you press it again, Git has no idea about your newer edits.