- Which
.gitignore pattern ignores the directories at any depth while leaving the regular file named release unignored? Answer: release/
When working with .gitignore patterns, the key distinction to understand is how Git differentiates between files and directories, and how the presence or absence of a leading slash affects matching depth.
A trailing slash in a .gitignore pattern tells Git to match only directories, never regular files. This is the critical insight for this question. Pattern A, release/, instructs Git to ignore any directory named release at any depth in the repository — so both release/ and examples/release/ get ignored. Crucially, because the pattern ends with /, Git will never apply it to the regular file named release, leaving that file untracked and available to git add. That's exactly the behavior the question requires, making A the correct answer.
Choice B, /release/, also matches only directories (due to the trailing slash), but the leading slash anchors the pattern to the repository root. This means only the top-level release/ directory gets ignored — examples/release/ would slip through unignored.
Choice C, release, has no trailing slash, so Git matches both files and directories named release at any depth. This would ignore the untracked source-data file, which must remain available — exactly the wrong behavior.
Choice D, /release, combines the anchoring problem of B with the file-matching problem of C: it only targets the root level, and it would match the regular file there too.
A useful rule of thumb: trailing slash = directories only, leading slash = root only. When you need to ignore directories at all depths without touching same-named files, reach for the plain name/ pattern.
- Which
.gitignore pattern most precisely ignores every generated directory named CMakeFiles at any depth without ignoring CMakeFilesNotes? Answer: **/CMakeFiles/
When working with .gitignore patterns, you need to understand two key mechanisms: path anchoring (where the pattern matches) and wildcard specificity (what the pattern matches). CMake build systems generate CMakeFiles/ directories at multiple levels, so your pattern must handle arbitrary depth while staying precise.
The correct choice is B — **/CMakeFiles/ — because ** in Git means "zero or more path segments at any depth." The trailing / ensures Git treats the match as a directory only, not a file. Critically, because the pattern ends exactly at CMakeFiles/, it won't match CMakeFilesNotes/, which has additional characters before the slash.
A (/CMakeFiles/) is wrong because the leading / anchors the pattern to the repository root only. It would catch build/CMakeFiles/ only if CMakeFiles sits at the top level — it completely misses tests/temp/CMakeFiles/ nested deeper.
C (**/CMakeFiles*) is wrong because the trailing * acts as a wildcard that matches any characters after CMakeFiles, including Notes. This would incorrectly ignore your docs/CMakeFilesNotes/ directory — exactly the trap the question warns about.
D (CMakeFiles/*) is wrong on two fronts: without a leading **/, it only matches at the root level, and it ignores the contents of the directory rather than the directory itself, which doesn't cleanly exclude the directory from tracking.
Study tip: In .gitignore, always distinguish between a leading / (anchors to root), **/ (matches any depth), and a trailing * (extends the match further than intended). When you need exact directory names, end your pattern with / and nothing else.
- How does this ignore rule affect the two binaries?
Answer: It ignores only examples/build/sample because the pattern is relative to examples/.gitignore.
When working with .gitignore files in Git, the critical concept to internalize is scope relativity: every .gitignore file applies rules relative to the directory it lives in, not the repository root — unless there's a root-level .gitignore.
The pattern /build/ in examples/.gitignore uses a leading slash, which anchors the match to prevent it from applying recursively into subdirectories. However, that anchor is relative to examples/, the directory containing the file. So /build/ means "match a directory called build directly inside examples/" — which is exactly examples/build/. That means examples/build/sample is ignored. The top-level build/app, however, lives outside examples/ entirely, so this rule never even sees it. Answer C is correct.
Answer A is wrong because it assumes /build/ is anchored to the repository root. That would only be true if the pattern appeared in a root-level .gitignore. Since it's in examples/.gitignore, its scope is examples/, not /.
Answer B makes a similar error — claiming leading slashes "always" refer to the repository root. Leading slashes anchor patterns to the .gitignore file's own directory, not globally.
Answer D is wrong in a different way: it invents a rule that doesn't exist. Nested .gitignore files absolutely can use leading slashes; those slashes just anchor relative to that file's directory, not the repo root.
Study tip: Always ask yourself, "Which directory does this .gitignore live in?" — that directory is the effective root for every pattern inside it, including slash-anchored ones.
- Which action correctly completes the change?
Answer: Run git rm -r --cached build/, then commit the staged removals and .gitignore.
When Git tracks a file, it stores a snapshot in its index (the staging area). Simply adding a path to .gitignore does not untrack already-committed files — .gitignore only prevents untracked files from being noticed. To stop tracking something that Git already knows about, you must explicitly remove it from the index while leaving the working directory untouched.
That's exactly what B accomplishes. git rm -r --cached build/ removes the entire directory from Git's index recursively (-r) without touching your local files (--cached). After running it, you stage those removals and commit them alongside the .gitignore update. From that point forward, Git ignores the directory entirely because it's no longer in the index and the ignore rule is in place.
A is incorrect because git reset build/ unstages pending changes to tracked files — it doesn't remove files from tracking altogether. The directory would still be tracked after the reset.
C is a trap. git clean -fdX build/ deletes files from your working directory that match .gitignore patterns. This is the opposite of what the developer needs — it would destroy the local build outputs they want to keep.
D manually deletes the directory, which would stage deletions but also wipe out local files. The scenario explicitly requires preserving local build outputs, so this violates the constraint entirely.
A useful mental rule: --cached means "index only, leave my files alone." Whenever you need to untrack something without deleting it, git rm --cached is your tool, paired with an updated .gitignore and a follow-up commit.
- Which statement correctly describes the effect of the new rule?
Answer: Git omits the untracked outputs by default, while the files remain local and the compiler can still update them.
When working with .gitignore, the key concept to internalize is that Git's ignore rules are purely about tracking and staging — they have no effect on your filesystem or any other tool's behavior.
Adding /build/ to .gitignore tells Git to stop noticing untracked files inside that directory. That's it. The files still exist on disk exactly as before, the compiler can read and write them freely, and nothing is deleted or moved. This is precisely what A describes: Git quietly skips those outputs during git status, git add, and commits, while the files remain fully accessible locally. Your next build command will overwrite or regenerate them just as it always has.
B is wrong because Git never deletes files during a commit — especially not ignored ones. Commits record snapshots of staged content; they don't clean your working directory. C reflects a fundamental misunderstanding: .gitignore is a Git concept, invisible to the compiler or any other process. The OS doesn't enforce ignore rules — Git simply chooses not to look at those paths. D is wrong on two counts: ignored files are not stored anywhere in Git history (not even "outside" it), and they absolutely do not appear in fresh clones, which is one of the primary reasons developers ignore build artifacts in the first place.
A useful mental model: think of .gitignore as a pair of blinders on Git's eyes, not a fence around the directory. Git can't see it, but everything else can. On exam questions about .gitignore, always ask yourself who or what is actually being restricted — it's always Git, never the filesystem.
- Which command most directly provides the required diagnostic information?
Answer: git check-ignore -v -- build/app
When debugging why Git ignores a specific file, you need a command that does two things simultaneously: confirms the file is being ignored and tells you exactly which pattern and which .gitignore file is responsible. This is a diagnostic task, so think about which Git command was specifically designed for tracing ignore behavior.
git check-ignore -v is precisely that tool. The -v (verbose) flag instructs Git to output not just whether the path is ignored, but the source file, the line number, and the matching pattern — everything you need to pinpoint the rule in a repository with nested .gitignore files. Option C is the correct answer because it directly surfaces the diagnostic information the developer requires.
Option A, git status --ignored, lists ignored files in the working tree but provides no information about which pattern caused the ignore — it's useful for discovery, not diagnosis. Option B, git diff -- .gitignore build/app, compares file content between versions; it has nothing to do with ignore-rule resolution and would confuse the developer entirely. Option D, git ls-files --stage, lists files in the index along with their staging metadata, but since build/app is ignored it likely won't appear at all, and this command says nothing about .gitignore patterns.
A useful memory aid: think of check-ignore as Git's "explain yourself" command for ignore rules. Whenever a question asks you to trace or diagnose why something is ignored — especially across multiple .gitignore files — git check-ignore -v with the file path is your go-to tool.
- Which root-level
.gitignore entry most precisely ignores only the generated root build directory? Answer: /build/
When working with .gitignore patterns, the key concept to understand is path anchoring — whether a pattern applies globally throughout the repository tree or is pinned to a specific location.
A leading slash (/) in a .gitignore pattern anchors it to the directory containing the .gitignore file. So /build/ means "ignore a directory named build only at the root level." This is exactly what the scenario needs: it protects examples/build/reference.txt because that build/ sits one level deeper and won't match the anchored pattern. A is the correct and most precise answer.
Now consider why the other options fall short. B (build/) has no leading slash, so Git treats it as a global pattern matching any build/ directory anywhere in the repository tree — including examples/build/. This would cause reference.txt to be ignored, breaking the requirement. C (**/build/) is even more aggressive: the ** wildcard explicitly matches build/ at any depth, zero or more levels down, which also catches examples/build/. D (*/build/) uses a single * wildcard, which matches exactly one path segment — so it would match something like examples/build/ but not the root-level build/ itself (since there's no preceding segment). This is both wrong in what it ignores and what it misses.
A useful tip: whenever a .gitignore question involves protecting a nested path while ignoring a same-named root path, immediately look for the leading slash anchor. If you see a pattern without / at the start, ask yourself "could this accidentally match something deeper in the tree?"
- Which ordered pair of
.gitignore rules satisfies the requirement? Answer: /artifacts/*
!/artifacts/.gitkeep
When working with .gitignore, the critical concept is rule ordering and negation. Git processes ignore rules top-to-bottom, and a negation rule (!) can only un-ignore a file if its parent directory isn't already fully ignored. This distinction — ignoring a directory versus ignoring its contents — is the heart of this question.
The correct approach in C works because /artifacts/* ignores everything inside the artifacts/ directory without ignoring the directory itself. Since the directory remains visible to Git, the subsequent !/artifacts/.gitkeep negation is valid and allows Git to track the placeholder file. This is the precise behavior the requirement describes.
A fails because /artifacts/ ignores the entire directory as an opaque object. Once a directory is fully ignored, no negation rule beneath it can reach individual files inside it — Git stops descending entirely. The !/artifacts/.gitkeep line becomes meaningless.
B has the right two rules but in the wrong order. Git reads rules sequentially, so !/artifacts/.gitkeep appears before anything is ignored — it negates nothing. Then /artifacts/* ignores all contents with no exception surviving, because the negation already fired before the ignore rule was established.
D uses !/artifacts/ first, which negates nothing (since the directory isn't ignored yet), then /artifacts/* ignores all contents with no working exception. The placeholder ends up ignored.
A useful mental rule: **you must ignore the contents (/artifacts/*), not the container (/artifacts/), before a negation exception can work.** Ignoring a whole directory is a dead end for negation.
- Which classification follows from the rules?
Answer: program.out and generated.out are ignored; expected.out is available to add.
When working with .gitignore files, the critical concept to internalize is that rules are processed top-to-bottom, and later rules override earlier ones. Git evaluates each file against every rule in sequence, and the last matching rule wins.
Starting with program.out: the first rule *.out matches it, so it's ignored. No later rule un-ignores it, so it stays ignored.
For tests/fixtures/expected.out: *.out initially ignores it, but the second rule !tests/fixtures/*.out is a negation that explicitly un-ignores .out files in that directory. Since no further rule re-ignores it, expected.out ends up available to add.
For tests/fixtures/generated.out: it follows the same path as expected.out — caught by rule one, freed by rule two — but then the third rule tests/fixtures/generated.out explicitly re-ignores it. That final specific rule wins, so generated.out is ignored. This confirms B as correct.
A is wrong because it claims both fixture files are available, ignoring that the third rule specifically re-ignores generated.out. C reflects a common misconception that the first matching rule "locks in" the result — Git doesn't work this way; last match wins. D is wrong because negation rules only affect files that previously matched an ignore pattern within a comparable scope; program.out is never targeted by !tests/fixtures/*.out since that negation is path-specific to the tests/fixtures/ directory.
As a study tip: whenever you see .gitignore questions with negation (!), trace each file through every rule in order and let the last match decide — never stop at the first hit.
- Which generated file is not ignored by these rules?
Answer: tools/solver
When reading .gitignore rules, the key distinction is between glob patterns (which match anywhere in the repository) and rooted patterns (which are anchored to the repository root). A pattern starting with / only matches at the root level — that's the critical insight for this question.
The rule /solver has a leading slash, meaning Git only ignores a file named solver directly in the root directory. The rule *.o matches any file ending in .o anywhere in the tree, and *.exe matches any file ending in .exe anywhere in the tree — neither of those has a leading slash, so they apply globally.
Now walk through each file: A — src/main.o matches *.o (the pattern applies everywhere, regardless of subdirectory), so it is ignored. B — solver sits in the root directory, so it matches /solver exactly and is ignored. C — solver.exe matches *.exe globally, so it is ignored. D — tools/solver is a file named solver inside a subdirectory. The /solver rule is anchored to the root and does not reach into subdirectories, and there is no unanchored solver pattern. So tools/solver is not ignored — making D the correct answer.
A useful tip: whenever you see a .gitignore pattern with a leading /, mentally append "root only" to remind yourself it won't cascade into subdirectories. Patterns without a leading slash (or containing an interior slash) behave differently and are worth knowing side-by-side for any exam covering version control tooling.