- Which action correctly applies the new ignore policy while leaving the local dependencies installed?
Answer: Run git rm -r --cached node_modules, then commit the index changes and .gitignore.
When Git is already tracking files, adding them to .gitignore does nothing to remove them from the index — Git continues watching every file it has already committed. This question tests whether you understand the difference between Git's tracking index and your working directory.
The fix is to remove files from the index without deleting them from disk. That's exactly what git rm -r --cached node_modules does: the --cached flag tells Git to stop tracking those files in the staging area while leaving your actual node_modules folder untouched. After running this command, you stage and commit both the index removals and your .gitignore, and from that point forward Git ignores the directory entirely. Option A is correct.
Option B uses git clean -fd, which deletes untracked files from your working directory — it would physically remove your installed dependencies, breaking your project. It also doesn't affect already-tracked files at all, so it doesn't solve the original problem either.
Option C's git reset --hard node_modules is not valid syntax for this purpose. git reset --hard resets your working tree and index to a previous commit state, which could overwrite local changes — it doesn't selectively untrack a directory.
Option D does the opposite of what you want: adding node_modules to the index again would deepen the problem, not fix it. You can't "commit once more before ignoring" — .gitignore doesn't retroactively untrack committed files.
The key pattern to remember: **.gitignore only prevents untracked files from being tracked. To untrack something already committed, you must explicitly remove it from the cache with --cached.**
- Which
.gitignore pattern most precisely ignores the generated directories without also ignoring same-named files? Answer: coverage/
When working with .gitignore patterns, the key distinction to understand is how Git differentiates between files and directories — and how trailing slashes control that behavior.
A trailing slash in a .gitignore pattern tells Git to match only directories, never files. So coverage/ will ignore any directory named coverage at any depth in the repository, while leaving an extensionless file named coverage completely trackable. That's exactly the behavior described in the prompt, making C the correct answer.
Here's why the other options fall short. A (coverage) is the most common trap — omitting the trailing slash means Git matches both files and directories named coverage, which would accidentally ignore the source files you need to keep. B (/coverage/) adds a leading slash, which anchors the pattern to the repository root only. This means nested coverage/ directories at deeper paths would be ignored, violating the "several depths" requirement. D (**/coverage) uses a double-asterisk glob to match at any depth, but without a trailing slash it matches both files and directories — same problem as option A, just with explicit depth-spanning syntax.
The nuance between B and C is worth noting: a leading slash restricts the pattern to the root, while no leading slash (with **/ being implicit) allows matching at any depth. The trailing slash is what restricts matching to directories only.
Study tip: Whenever a .gitignore question involves protecting same-named files while ignoring directories, immediately look for the trailing slash — it's the only mechanism that creates a file-vs-directory distinction in Git's pattern matching.
- Where should the team place these patterns?
Answer: In the repository's tracked root .gitignore file
When dealing with Git ignore rules, the key question to ask is: who needs this rule, and where should it live? The passage gives you two critical constraints — the rule must be versioned with the project and must not affect other repositories.
A tracked .gitignore file in the repository root satisfies both constraints perfectly. Because it's committed to the repository, every contributor automatically receives it when they clone — no manual setup required. Git reads .gitignore files as part of the repository itself, so the rules are scoped entirely to that project. B is correct.
Here's why the other options fall short. A — a global Git excludes file (usually ~/.config/git/ignore) — lives on an individual machine and applies to every repository that contributor works in, directly violating the "must not affect unrelated repositories" constraint. It also isn't versioned, so new contributors don't get it automatically. C — .git/info/exclude — is local to one clone of the repository and is never committed (the .git/ directory is never tracked), so other contributors never see those rules. It's useful for personal, one-off ignores but fails the "versioned with the project" requirement. D — npm configuration — controls package manager behavior like registry URLs and authentication, not Git's file-tracking behavior. It has nothing to do with .gitignore patterns.
A useful rule of thumb: if an ignore pattern is relevant to everyone working on the project (like build artifacts and dependencies), it belongs in the committed .gitignore. Save global or local excludes for personal preferences that shouldn't be imposed on the whole team.
- Which files appear in ordinary
git status output as untracked? Answer: Only src/app.js appears as an untracked file.
When reading .gitignore files, Git processes rules in order, and later rules can override earlier ones — but with one critical constraint: a negation rule (!pattern) cannot un-ignore a file whose parent directory is already ignored.
Here's how each file gets evaluated against your three rules (*.js → !src/** → src/generated/):
**test/helper.js** matches *.js and is never negated — it's ignored. It won't appear as untracked.
**src/app.js** matches *.js, but then !src/** negates that, whitelisting everything under src/. It's no longer ignored, so it does appear as untracked.
**src/generated/api.js** first matches *.js, then !src/** would negate it — but then src/generated/ re-ignores the entire directory. Because src/generated/ is an ignored directory, Git stops descending into it entirely. Even though api.js individually might qualify for the negation, its parent folder is ignored, and Git never inspects the contents. It disappears from git status completely.
That makes D correct — only src/app.js appears as untracked.
A is wrong because test/helper.js is ignored by *.js with no negation. B is wrong because src/generated/api.js is inside an ignored directory and never surfaces. C combines both of those errors, assuming the !src/** negation reaches inside src/generated/ even after it's been re-ignored as a directory.
The key study tip: negation rules cannot rescue files from inside an ignored directory. If any ancestor folder is ignored, Git won't look inside — period. Always trace the parent directories, not just the file itself.
- Which change most directly produces the intended result?
Answer: Remove *.lock and keep both directory patterns.
When working with .gitignore, you need to think carefully about pattern scope — a single pattern can accidentally exclude more files than you intend. The goal here is to commit package-lock.json while still ignoring other lock files and keeping node_modules/ and dist/ excluded.
The pattern *.lock is the problem. It matches any file ending in .lock, which includes package-lock.json — causing Git to ignore a file the team explicitly wants tracked. Removing *.lock entirely (answer C) eliminates this overly broad pattern, allowing package-lock.json to be committed while node_modules/ and dist/ remain ignored. This directly achieves the team's stated goal.
Answer A is wrong because removing node_modules/ would cause npm's dependency folder to be tracked by Git — exactly what the team wants to avoid. Keeping *.lock still blocks package-lock.json.
Answer B is wrong for similar reasons: removing dist/ exposes build output to version control, which the team explicitly doesn't want. Again, *.lock still silently ignores package-lock.json.
Answer D is a clever-sounding trap. Replacing *.lock with package-lock.json would ignore that file by name — the opposite of what's needed. The team wants package-lock.json committed, not ignored.
A useful rule of thumb: whenever you see a glob pattern in .gitignore, ask yourself "what else does this match?" Wildcards can silently exclude important files. When a specific file needs to be tracked, the cleanest fix is removing the pattern that blocks it — not adding a new one.
- Which root
.gitignore configuration meets these requirements? Answer: node_modules/
/dist/
When working with .gitignore, the critical distinction is between anchored and unanchored patterns. A leading slash (/) anchors a pattern to the directory containing the .gitignore file, meaning it only matches at that specific location. Without a leading slash, the pattern matches recursively — anywhere in the repository tree.
For this monorepo scenario, the requirements are asymmetric: ignore node_modules everywhere, but ignore dist only at the root level. Answer A (node_modules/ and /dist/) handles this perfectly. The unanchored node_modules/ matches every node_modules directory at any depth, while /dist/ is anchored to the root, leaving package-level dist directories unaffected.
Answer B uses /node_modules/, which anchors that pattern to the root as well — so nested node_modules directories inside packages would not be ignored. That breaks the first requirement. Answer C uses an unanchored dist/, which would ignore every dist directory throughout the repo, not just the root-level one — violating the second requirement. Answer D combines both mistakes: anchored node_modules/ (misses nested ones) and unanchored dist/ (ignores all dist folders).
A useful mental model: think of a leading / as saying "only right here." No leading slash means "everywhere below." So whenever you see a .gitignore question with mixed scope requirements — some patterns global, some local — check whether each pattern's anchoring matches its intended reach. That asymmetry is exactly what separates the correct answer from three plausible-looking distractors.
- Which pair of root
.gitignore rules supports this exception? Answer: /dist/*
!/dist/release-manifest.json
When working with .gitignore, order matters enormously — Git processes rules sequentially, and a later rule can override an earlier one. The key mechanic here is that you cannot un-ignore a file inside an ignored directory. If Git ignores an entire directory (using a trailing /), it never even looks inside to evaluate exceptions. This is the central trap in this question.
Option C is correct because /dist/* ignores the contents of dist without ignoring the directory itself. Git still descends into dist, sees release-manifest.json, and evaluates the next rule !/dist/release-manifest.json, which successfully un-ignores it. The wildcard * matches everything directly inside dist, but the negation pattern can still override it since the directory remains traversable.
Option A fails for exactly the reason described above. /dist/ tells Git to ignore the entire dist directory as a unit. Once a directory is ignored this way, Git stops traversing it entirely — the negation rule !/dist/release-manifest.json is never evaluated, so the manifest gets ignored anyway.
Option B has the right rules but the wrong order. The negation !/dist/release-manifest.json appears before /dist/*, so it's overridden by the wildcard that comes after. Git reads rules top-to-bottom, and later rules win.
Option D uses /dist/*.json, which only ignores JSON files in dist, leaving all other file types (binaries, logs, etc.) untracked — this doesn't satisfy the requirement to ignore everything except the manifest.
Remember this rule of thumb: use dir/* (not dir/) when you need to ignore contents but still allow exceptions inside that directory.
- Which root
.gitignore pattern best implements this policy? Answer: **/dist/**/*.map
When working with .gitignore patterns, the key skill is understanding how glob syntax controls where a pattern matches, not just what it matches. You need to think carefully about directory scope and file specificity simultaneously.
The policy has two requirements: ignore .map files inside any dist directory (root-level or nested in packages), but leave .map files elsewhere trackable. Pattern A — **/dist/**/*.map — satisfies both conditions precisely. The leading **/ means "match at any depth in the repository," so dist directories at the root or inside packages/foo/dist are both covered. The **/*.map tail ensures only .map files inside dist are affected, not the bundled .js files alongside them.
Each wrong answer fails in a specific way. B (**/*.map) is too broad — it ignores every .map file in the entire repository, including source maps for files outside dist that should remain trackable. C (/dist/**/*.map) is too narrow — the leading / anchors the pattern to the repository root only, so packages/foo/dist/bundle.map would slip through unignored. D (**/dist/) ignores the entire dist directory tree, which contradicts the policy of still tracking the bundled .js files inside it — only the .map files should be excluded.
A useful study tip: when a .gitignore question mentions "at any depth," that's your cue that **/ belongs at the front. When it says "only files of a specific extension within a folder," you need both a directory segment and a file extension glob — exactly what pattern A combines.
- Which conclusion is most accurate?
Answer: The artifact remains on disk and may enter the archive despite being ignored by Git.
When working with Git, it's crucial to understand the exact scope of what .gitignore actually controls — and what it doesn't. .gitignore is purely a Git concept: it tells Git which files to exclude from version tracking and status reporting. It has absolutely no authority over your filesystem or any external tools that interact with your project directory.
Here's the key insight: dist/app.js still physically exists on disk. Git simply pretends not to see it. When your deployment script archives the entire working directory, it's reading the filesystem directly — not asking Git which files matter. So the ignored file is just another file sitting in a folder, fully eligible to be swept into that archive. That makes D the correct conclusion.
A is wrong because .gitignore doesn't automatically exclude files from any archive — only Git-aware operations (like git archive) respect ignore rules. A generic archiving script has no knowledge of .gitignore whatsoever.
B describes a behavior Git never performs. Matching a file against .gitignore never deletes or modifies that file. Git is non-destructive with untracked files by default; it simply ignores them.
C is a subtle trap. "Tracked silently" implies Git is secretly recording the file somewhere, which is false. An ignored file is genuinely outside Git's tracking system — it doesn't appear in commits, the index, or any hidden internal state.
The study tip to remember: .gitignore controls Git's awareness, not the filesystem itself. Whenever a question involves non-Git tools (build scripts, archivers, CI pipelines) accessing your project folder, assume ignored files are still fair game.
- Which pattern should be placed in
packages/web/.gitignore? Answer: /build/
When working with .gitignore files in nested directories, the key concept to understand is how the leading slash (/) anchors a pattern relative to the location of the .gitignore file itself.
A pattern starting with / is anchored to the directory containing that .gitignore file — it won't match anything in subdirectories. So /build/ placed in packages/web/.gitignore matches only packages/web/build/, which is exactly the desired behavior here. That makes B the correct answer.
Here's why the other options fall short: A (build/) without a leading slash matches build/ anywhere beneath packages/web/, so it would also ignore packages/web/examples/demo/build/ — catching more than intended. C (**/build/) is even more aggressive; the ** glob explicitly matches across all subdirectory depths, so it would ignore every build/ folder under packages/web/, again capturing the examples/demo/build/ directory you want to keep. D (/packages/web/build/) is the classic trap of writing a path relative to the repository root inside a nested .gitignore. Because the leading slash anchors to the file's own directory, Git would look for a literal folder named packages/web/build inside packages/web/ — i.e., packages/web/packages/web/build/ — which doesn't exist.
A good rule of thumb: in any .gitignore, the leading / means "starting from right here." When you need to ignore something only at the current directory level (not recursively), always prefix the pattern with /. This distinction between anchored and unanchored patterns is a frequent source of bugs in monorepo configurations.