R Programming Quiz: Git Commits
10 questions · exam conditions
0:00
Git CommitsQuestion 1 of 10

Before committing an R analysis, a researcher notices that data/patients.csv, which contains confidential raw records, was accidentally staged with the code. The file has never been committed, and repository policy requires raw patient data to remain outside Git.

Which workflow best prevents the data from entering repository history while preserving the intended code changes?

Commit everything, delete the CSV in a second commit, and add its path to .gitignore afterward.
Remove the CSV from staging, add its path to .gitignore, review the staged snapshot, and commit the code.
Add the CSV path to .gitignore while it remains staged, then commit the currently staged snapshot.
Commit everything on a temporary branch, remove the CSV there, and merge only the final branch state.
← Back to quizzes

R Programming Quiz

R Programming Quiz: Git Commits

Practice Git Commits in R Programming with focused quiz questions that help you check what you know, review explanations, and build confidence with test-style prompts.

What this quiz covers

This quiz focuses on Git Commits, giving you a quick way to practice the rules, question types, and explanations that matter most for R Programming.

How to use this quiz

Try each quiz question before looking at the correct answer. Use the explanations to review missed ideas, then come back to similar questions until the pattern feels familiar.

All questions

Question 1

Before committing an R analysis, a researcher notices that data/patients.csv, which contains confidential raw records, was accidentally staged with the code. The file has never been committed, and repository policy requires raw patient data to remain outside Git.

Which workflow best prevents the data from entering repository history while preserving the intended code changes?

  1. Commit everything, delete the CSV in a second commit, and add its path to .gitignore afterward.
  2. Remove the CSV from staging, add its path to .gitignore, review the staged snapshot, and commit the code. (correct answer)
  3. Add the CSV path to .gitignore while it remains staged, then commit the currently staged snapshot.
  4. Commit everything on a temporary branch, remove the CSV there, and merge only the final branch state.
Explanation: When working with Git, the critical principle to internalize is that once data enters a commit, it lives in repository history permanently — even if deleted later. Questions like this test whether you understand the distinction between Git's staging area and committed history. The safest workflow is option B. By first running git restore --staged data/patients.csv (or git reset HEAD), you remove the file from staging without touching the working directory. Then adding its path to .gitignore ensures future git add commands won't accidentally re-stage it. Finally, reviewing the staged snapshot before committing confirms only the intended code changes are captured — the patient data never touches history at all. Option A is dangerous precisely because it does commit the CSV first. Even after deleting it in a second commit and adding .gitignore, the raw patient data exists permanently in the earlier commit's history. Anyone with repository access can retrieve it by checking out that commit. Option C is a common misconception: .gitignore only prevents untracked files from being staged. If a file is already staged, .gitignore has no effect on that staged snapshot — committing would still include the CSV. Option D introduces unnecessary complexity and the same core risk as A: the CSV enters history on the temporary branch. Even if that branch is eventually deleted, orphaned commits can persist in certain Git configurations. A useful rule of thumb: treat Git history as immutable and public. Preventing sensitive data from entering a commit is always simpler than trying to scrub it afterward.

Question 2

An API change adds a na_policy argument to an exported R function. The implementation, regression tests, and vignette example must change together for the new behavior to be usable. A separate parser optimization is also ready.

Which commit organization best reflects the logical changes?

  1. Commit each file separately, then commit the parser optimization with whichever file was modified last.
  2. Commit all source files together, then place tests, documentation, and optimization in a second commit.
  3. Commit the API implementation, tests, and vignette together, then commit the parser optimization separately. (correct answer)
  4. Commit the implementation and optimization together, then add tests and the vignette in later independent commits.
Explanation: When organizing commits in a version-controlled project, the guiding principle is logical cohesion: each commit should represent one complete, self-contained unit of change that could be understood, reviewed, or reverted independently. This question tests whether you can identify which files belong together conceptually versus which should be separated. The na_policy API change is a single logical feature. The implementation (source code), regression tests, and vignette example are inseparable — if you merge only the implementation without the tests, your CI pipeline may not validate the behavior; without the vignette update, users can't discover or use the new argument correctly. These three pieces form one atomic unit. The parser optimization, however, is a distinct concern with no dependency on the API change. Keeping it in its own commit makes it easier to review, bisect if it introduces a bug, and understand in isolation. This makes C the correct organization. A is wrong because committing each file separately fragments a single logical change into meaningless micro-commits, and arbitrarily bundling the optimization with the "last modified file" destroys traceability. B groups all source files together but separates tests and documentation into a second commit — this breaks the atomic unit of the na_policy feature, leaving a commit where the code exists but isn't yet validated or documented. D compounds the problem by mixing the API implementation with the unrelated optimization, then deferring tests and docs — you'd have a commit that's both logically impure and incomplete. A useful rule of thumb: ask yourself "if I revert this commit, does the codebase remain in a coherent, working state?" If not, your commit boundaries are wrong.

Question 3

A developer has staged selected lines from R/model.R, but other experimental edits in the same file remain unstaged. Before committing, the developer wants to verify exactly what the commit will record rather than reviewing all working-tree differences.

Which review step most directly verifies the proposed commit?

  1. Inspect the ordinary working-tree diff, because it shows all differences between the current file contents and the last commit, including what will be committed.
  2. Read the most recent commit diff, because the next commit will contain every change made since that commit.
  3. Open the file in the editor, because its current contents exactly match the staged version Git will commit.
  4. Inspect the staged diff, because it compares the index against the current committed snapshot and shows precisely what will be recorded. (correct answer)
Explanation: When working with Git, it's essential to understand the distinction between three different "snapshots" of your code: the last commit (HEAD), the index (staging area), and the working tree. Questions like this test whether you know which Git command targets each layer — and specifically, which one reflects what will actually be saved in the next commit. The staging area (index) is the key concept here. When you run git add on specific lines or hunks, only those changes move into the index. The next commit records exactly what's in the index — nothing more, nothing less. So to verify the proposed commit, you need to compare the index against HEAD. That's precisely what git diff --staged (or git diff --cached) does, making D the correct answer. A is wrong because git diff (without --staged) compares the working tree to the index, not the index to HEAD. It shows unstaged changes — the experimental edits the developer intentionally excluded from staging — so it misrepresents what will be committed. B is wrong because the most recent commit diff shows what was already recorded, not what's pending. The next commit won't contain everything since the last commit; it contains only what's staged. C is wrong because the file on disk reflects the working tree, which includes both staged and unstaged changes mixed together. Opening the file gives you no way to isolate the staged-only version. As a study tip: always match your Git command to the correct layer. Staged diff = index vs. HEAD = what commits. Burn that mapping in, and these questions become straightforward.

Question 4

A faulty commit on a shared branch changed a statistical threshold from 0.05 to 0.5. The team decides to undo that entire commit while preserving a visible record that the change was introduced and later reversed.

Which action best satisfies the team's goal?

  1. Reset the branch to the parent of the faulty commit and force-push the shortened history.
  2. Create a revert commit whose message explains that the incorrect threshold change is being undone. (correct answer)
  3. Amend the faulty commit so it uses the original threshold, then replace the shared branch history.
  4. Edit the threshold locally without committing, because the earlier commit already documents the change.
Explanation: When working with shared branches in version control, the key question to ask yourself is: does this action preserve history or rewrite it? On a shared branch, rewriting history creates problems for collaborators whose local copies no longer match the remote. The safer, professional approach is to add new commits rather than alter existing ones. Creating a revert commit — option B — is exactly the right tool here. Git's revert command generates a new commit that applies the inverse of a previous commit's changes, bringing the code back to the original threshold of 0.05. Crucially, both the faulty commit and the revert commit remain visible in the log, giving the team a transparent record that the bad change was introduced and then corrected. This satisfies both goals the question specifies: undoing the change and preserving a visible audit trail. Option A fails because reset followed by a force-push rewrites the shared branch's history, erasing the faulty commit entirely. That breaks collaborators' local branches and destroys the audit trail the team explicitly wants. Option C has the same fundamental problem — amending a commit rewrites history, and replacing the shared branch's history causes the same disruption to teammates, even if the code itself ends up correct. Option D is a trap: leaving a change uncommitted means it exists only as an unstaged local modification, which neither documents nor reverses anything in the project's permanent history. A useful rule of thumb: never rewrite history on a shared branch. When you need to undo something collaboratively, always reach for git revert, not git reset or --amend.

Question 5

An analyst runs git status and sees R/clean_sales.R under Changes to be committed, reports/summary.Rmd under Changes not staged for commit, and scratch/output.csv under Untracked files. The analyst then creates a commit without specifying any paths.

Which files will the new commit contain?

  1. All three files, because a commit snapshots the entire working directory.
  2. Only R/clean_sales.R, because it is the only change currently staged. (correct answer)
  3. R/clean_sales.R and reports/summary.Rmd, because both are tracked files.
  4. reports/summary.Rmd and scratch/output.csv, because neither has been committed before.
Explanation: When working with Git, the key mental model is the three-zone system: your working directory, the staging area (also called the index), and the committed history. A commit only captures what's in the staging area — nothing more, nothing less. In this scenario, git status reveals exactly which zone each file occupies. R/clean_sales.R appears under "Changes to be committed," meaning it has been explicitly staged with git add. That's the only file living in the staging area. When the analyst runs git commit without specifying paths, Git packages precisely what's staged — making B correct. Each distractor reflects a common misconception worth understanding. A is wrong because Git commits are not automatic snapshots of your entire working directory — that's a fundamental misunderstanding of how Git works. You must explicitly stage changes before they enter a commit. C is wrong because "tracked" simply means Git is aware of a file's history; being tracked does not automatically stage modifications. reports/summary.Rmd was modified but never staged, so it stays out of the commit. D is wrong on two counts: reports/summary.Rmd is already tracked (it has prior commits), and scratch/output.csv is untracked, meaning Git ignores it entirely until you explicitly git add it. A useful habit: before every commit, mentally read git status top-to-bottom and ask yourself, "What's actually under Changes to be committed?" Only that section feeds into your next commit — everything else is just noise until you stage it.

Question 6

In an R package, a developer changes an exported function's arguments and updates its roxygen comments. Repository policy tracks generated .Rd files, and the developer regenerates only the corresponding help page. An unrelated generated help page is also modified because it was produced with a different tool version.

What should the developer include in the commit for the function change?

  1. The function, its roxygen comments, and the corresponding regenerated .Rd file, excluding the unrelated help-page change. (correct answer)
  2. Only the function and roxygen comments, because generated documentation should never be committed to any repository.
  3. Only the regenerated .Rd files, because they represent the user-visible result of the documentation process.
  4. The function and every modified help page, because all generated outputs should always be committed together.
Explanation: When working with R packages, you need to think carefully about what belongs in a commit — specifically, distinguishing between source files you author, generated files your repository tracks, and generated files that changed for unrelated reasons. In this scenario, the repository policy explicitly tracks .Rd files, which means committing the regenerated help page corresponding to your function change is correct and expected. The source of truth for that change includes the function itself, its roxygen comments (the human-authored documentation source), and the .Rd file generated directly from those comments. Together, these three components form a complete, coherent unit of change. Answer A captures exactly this — the function, its roxygen comments, and its corresponding .Rd file — while deliberately excluding the unrelated help-page modification. Answer B is wrong because it treats "generated file" as a category that should never be committed. That's a blanket rule that doesn't apply here; the repository policy explicitly tracks .Rd files, so excluding them would leave the repo in an inconsistent state. Answer C goes too far in the other direction by committing only the generated output, which would orphan the source change — anyone reviewing history couldn't understand why the .Rd changed. Answer D fails because it bundles in an unrelated modification caused by a tool version difference. Including that change would conflate two separate concerns and make the commit history misleading and harder to review. A useful rule of thumb: a commit should capture one logical change, completely. If a file changed for a different reason — even if it's the same file type — it belongs in a separate commit.

Question 7

A commit changes a bootstrap routine to accept a seed explicitly because parallel workers previously produced non-reproducible results. The work is associated with issue 318.

Which commit message best communicates the change to a future maintainer?

  1. Issue 318: update bootstrap.R, helpers.R, and test-bootstrap.R
  2. Fix reproducibility problem and make several necessary code updates
  3. Accept an explicit seed to reproduce parallel bootstrap results (refs #318) (correct answer)
  4. Change bootstrap seed handling because the previous implementation was old
Explanation: When evaluating commit messages, ask yourself: will a future maintainer understand what changed, why it changed, and how to find more context? A strong commit message answers all three without forcing someone to dig through the diff. Option C does exactly this. It states what changed ("accept an explicit seed"), explains why ("to reproduce parallel bootstrap results"), and links to the originating issue (refs #318). A maintainer reading the git log months later immediately understands the motivation and can trace the full discussion in issue 318 if needed. That's the gold standard. Option A fails because it lists files rather than intent. Naming bootstrap.R, helpers.R, and test-bootstrap.R tells you the scope of the diff, which git already shows you — it says nothing about why those files changed or what problem was solved. File-listing commits are a common anti-pattern. Option B gestures at the problem ("reproducibility") but stays vague ("several necessary code updates"). The phrase "necessary" is circular — of course updates were necessary, that's why there's a commit. Without the seed detail or the issue reference, a future maintainer has little actionable information. Option D is arguably worse than B because it introduces a misleading justification. Saying the "previous implementation was old" implies the change was a routine modernization, not a correctness fix for a real reproducibility bug. Inaccurate commit messages are more dangerous than vague ones because they actively misdirect future readers. As a study tip, remember the formula: what changed + why it matters + where to learn more. Any commit message missing two of those three elements is likely a wrong answer.

Question 8

A developer discovers that a commit already pushed to a shared branch incorrectly drops rows containing valid zero values. Other team members may already have based work on that commit. The developer has corrected the filtering logic locally.

What is the most appropriate next step?

  1. Amend the original commit and force-push it so the branch appears to have always been correct.
  2. Reset the shared branch before the original commit and force-push both changes as one replacement commit.
  3. Leave the correction uncommitted and explain the original commit's limitation in a team message.
  4. Create a new commit describing the zero-value filtering correction, then push it normally. (correct answer)
Explanation: When working with shared Git branches, the guiding principle is never rewrite history that others may already depend on. Any time a commit has been pushed to a shared branch, treat it as immutable — team members may have pulled it, branched from it, or built work on top of it. The right move here is D: create a new commit that corrects the zero-value filtering logic and push it normally. This preserves the full history of what happened, makes the fix visible and traceable, and avoids disrupting anyone else's local repository. A clear commit message describing the correction also serves as documentation for future developers who might wonder why the filtering behavior changed. A is a dangerous trap. Amending a pushed commit and force-pushing rewrites shared history, which causes teammates' local branches to diverge from the remote — leading to confusing merge conflicts and potentially lost work. Force-pushing onto a shared branch is almost never appropriate. B makes the same fundamental mistake as A, just at an earlier point in history. Resetting and force-pushing is even more destructive because it discards more commits from the shared timeline, compounding the risk of breaking teammates' work. C avoids rewriting history, which is good, but leaving a known bug uncorrected in the codebase — with only a team message as mitigation — is irresponsible. Code should reflect its correct intended behavior, not rely on tribal knowledge passed through chat. A useful rule of thumb: if it's been pushed, fix forward, never fix backward. New commits are always the safe correction mechanism on shared branches.

Question 9

A function previously returned NaN when every value in a group was missing. It has been changed to return NA_real_, matching the package's documented missing-value convention.

Which commit subject most meaningfully describes this change?

  1. Update function and tests for the latest analysis requirements
  2. Fix files related to missing values in grouped calculations
  3. Return NA_real_ for groups containing only missing values (correct answer)
  4. Modify R/summarize_groups.R and tests/test-summary.R
Explanation: When writing commit messages, the goal is to communicate what changed and why — not just where or that something happened. A good commit subject gives a future reader enough information to understand the change without opening the diff. Option C captures exactly this: "Return NA_real_ for groups containing only missing values" tells you the specific behavior that changed (the return value), the specific condition that triggers it (all-missing groups), and implicitly the reason (correcting the output type). This is precise, actionable, and self-contained — a developer skimming the git log immediately understands the fix. Option A fails because it's vague to the point of being meaningless. "Latest analysis requirements" could describe almost any change in any codebase. It gives no information about what actually changed or how. Option B is slightly better — it mentions missing values — but "fix files related to" is still frustratingly vague. It tells you the general topic but not the actual behavior that was corrected. You'd still have to open the commit to understand what was done. Option D commits the classic mistake of describing which files changed rather than what the change means. File names belong in the diff, not the subject line. Any meaningful commit touches files; that's not useful information on its own. A useful study tip: when evaluating commit messages, ask yourself "could a developer understand this change without reading the code?" If the answer is no, the message is too vague. The best commit subjects describe behavior changes in concrete, specific terms — preferably matching the exact terminology used in the codebase, as C does with NA_real_.

Question 10

While fixing an incorrect join in R/merge_customers.R, a developer also reformats several unrelated plotting functions. The join fix has a focused regression test, and both groups of changes are currently unstaged.

Which commit workflow would produce the most useful project history?

  1. Stage the join fix and its test for one commit, then commit the unrelated formatting separately. (correct answer)
  2. Stage every modified file and create one commit describing both the join fix and the formatting.
  3. Commit the regression test first, then commit the join fix together with all formatting changes.
  4. Commit only the join implementation now and leave both the test and formatting uncommitted indefinitely.
Explanation: When working with version control in R projects, the key principle to apply is atomic commits — each commit should represent one logical, self-contained change. Ask yourself: "If someone bisects this history to find a bug, does each commit tell a clear story?" The best workflow here is A: stage the join fix alongside its regression test as one commit, then commit the formatting changes separately. These two groups of changes have entirely different purposes. The join fix (plus its test) is a meaningful, testable unit — the test validates the fix, so they belong together. The formatting changes are cosmetic and unrelated. Keeping them in separate commits means future developers (or future you) can revert the formatting without touching the logic, and vice versa. B is tempting because it feels efficient, but bundling unrelated changes into one commit creates noise. If the join fix later causes a regression, reverting that commit also undoes the formatting work — an unnecessary headache. Mixed commits obscure project history. C has the order backwards. Committing a regression test before the fix it validates means your repository briefly contains a failing test, which breaks the principle that each commit should leave the project in a working state. The fix and its test form one logical unit and should travel together. D is simply procrastination disguised as a workflow. Leaving both the test and formatting uncommitted indefinitely defeats the purpose of version control and risks losing work. A good study tip: whenever you see a question about commit strategy, evaluate each option against two questions — "Is this commit atomic?" and "Does this commit leave the project in a valid state?"