{"id":"l-git-4-2","courseId":"git-github","lang":"en","kind":"lesson","summary":"Park unfinished work with git stash and bring it back later, and write a .gitignore that keeps dependencies, build output, secrets and OS clutter out of your repository.","html":"<p>Two small tools keep a working tree under control. <code dir=\"ltr\">git stash</code> gives you a drawer for work that isn’t ready to commit. <code dir=\"ltr\">.gitignore</code> tells Git which files it should never track at all. Both prevent the same kind of accident: the wrong thing ending up in a commit.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Stash: a drawer for unfinished work</h2>\n<p>You’re halfway through the portfolio’s contact form on the <code dir=\"ltr\">contact-form</code> branch when someone points out a typo on the live home page. You need <code dir=\"ltr\">main</code>, now. But <code dir=\"ltr\">git switch main</code> refuses, because your edits to <code dir=\"ltr\">index.html</code> would be overwritten, and you don’t want to commit a half-built form.</p>\n<p>Stash it:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> push</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -m</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"contact form: fields done, validation next\"</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> status</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">        # nothing to commit, working tree clean</span></span></code></pre></div>\n<p>Your changes, staged and unstaged, are saved in a stash entry and removed from the working tree. Now fix the typo:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> main</span></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\"># fix, commit, push</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> switch</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> contact-form</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> pop</span></span></code></pre></div>\n<p><code dir=\"ltr\">pop</code> reapplies the most recent stash and deletes it. You’re back exactly where you were.</p>\n<p>The other stash commands you’ll use:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> list</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">                  # stash@{0}: On contact-form: contact form: fields done…</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> show</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -p</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash@{</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">     # the diff inside a stash</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> apply</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash@{</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">       # reapply but keep the stash</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> drop</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash@{</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">}</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">        # delete one stash</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> stash</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> push</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -u</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -m</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"…\"</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">        # include untracked (new) files too</span></span></code></pre></div>\n<p>That last flag matters. By default stash only saves changes to <strong>tracked</strong> files. A brand-new <code dir=\"ltr\">contact.js</code> stays in your folder, untouched, which surprises people when they pop and it isn’t “restored”. Use <code dir=\"ltr\">-u</code> whenever you’ve created files.</p>\n<p>Stashes aren’t tied to a branch: you can pop one onto any branch, which is occasionally handy and occasionally a surprise. If you realise the stashed work deserves its own branch after all, <code dir=\"ltr\">git stash branch contact-validation</code> creates a branch at the commit where you stashed, applies the stash there and drops it, which sidesteps conflicts with anything that has changed since.</p>\n<p>If <code dir=\"ltr\">pop</code> hits a conflict, Git applies what it can, marks the conflict as usual, and keeps the stash instead of dropping it. Resolve, <code dir=\"ltr\">git add</code>, and run <code dir=\"ltr\">git stash drop</code> once you’re sure.</p>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><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\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">Tip</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Stash is for minutes, not weeks</span></p>\n<p>A stash has no branch and no pull request, and an old one with a vague message is a mystery. For anything you’ll leave overnight, make a commit on your branch instead (<code dir=\"ltr\">git commit -m &quot;WIP: contact validation&quot;</code>) and amend or squash it later. Use <code dir=\"ltr\">-m</code> on every stash so <code dir=\"ltr\">git stash list</code> tells you what each one is.</p>\n</aside>\n<h2 id=\"sec-2\" tabindex=\"-1\">.gitignore: files Git should never track</h2>\n<p>Some files belong in your project folder but never in history:</p>\n<ul>\n<li>dependencies you can reinstall, such as <code dir=\"ltr\">node_modules/</code>;</li>\n<li>build output you can regenerate, such as <code dir=\"ltr\">dist/</code>;</li>\n<li>secrets and machine-specific settings, such as <code dir=\"ltr\">.env</code>;</li>\n<li>clutter from your OS and editor, such as <code dir=\"ltr\">.DS_Store</code> on macOS.</li>\n</ul>\n<p>List them in a file called <code dir=\"ltr\">.gitignore</code> at the repository root and commit it, so everyone on the project shares the rules:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">.gitignore</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># Dependencies\nnode_modules/\n\n# Build output\n/dist/\n\n# Local environment and secrets\n.env\n.env.*\n!.env.example\n\n# OS and editor files\n.DS_Store\n*.log</code></pre></div>\n<p>Ignored files disappear from <code dir=\"ltr\">git status</code> and <code dir=\"ltr\">git add .</code> skips them.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">How patterns work</h2>\n<p>Each line is a pattern, matched against paths relative to the <code dir=\"ltr\">.gitignore</code> file’s folder:</p>\n<ul>\n<li><code dir=\"ltr\">#</code> starts a comment, but only at the beginning of a line. Blank lines are ignored.</li>\n<li><code dir=\"ltr\">*.log</code> matches any file ending in <code dir=\"ltr\">.log</code>, in any folder.</li>\n<li>A trailing <code dir=\"ltr\">/</code> matches directories only: <code dir=\"ltr\">node_modules/</code>.</li>\n<li>A leading <code dir=\"ltr\">/</code> anchors the pattern to this folder: <code dir=\"ltr\">/dist/</code> ignores the root <code dir=\"ltr\">dist</code> but not <code dir=\"ltr\">src/dist</code>.</li>\n<li><code dir=\"ltr\">**/</code> matches any depth: <code dir=\"ltr\">**/fixtures/*.json</code>.</li>\n<li><code dir=\"ltr\">!</code> re-includes something an earlier line excluded: <code dir=\"ltr\">!.env.example</code> keeps the template for other developers. It can’t re-include a file whose parent <em>folder</em> is excluded, because Git never looks inside an ignored folder.</li>\n</ul>\n<p>When a file is ignored and you don’t know why, ask Git:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> check-ignore</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -v</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> dist/app.js</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"5\"><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>.gitignore:5:/dist/\tdist/app.js</code></pre></div>\n<p>It prints the file, line number and pattern responsible.</p>\n<p>For clutter that only your machine creates, don’t burden every project’s <code dir=\"ltr\">.gitignore</code>. Git also reads a global ignore file, <code dir=\"ltr\">~/.config/git/ignore</code>, which is a good home for <code dir=\"ltr\">.DS_Store</code> and editor folders. GitHub keeps a collection of starter <code dir=\"ltr\">.gitignore</code> templates for most languages, and offers one when you create a repository.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">Ignoring doesn’t untrack</h2>\n<p><code dir=\"ltr\">.gitignore</code> only affects <strong>untracked</strong> files. If <code dir=\"ltr\">.env</code> was committed before you ignored it, Git keeps tracking it. Remove it from the index and commit, which keeps your local file:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"6\"><div class=\"code-head\"><span class=\"code-title\">Terminal</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><span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> rm</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --cached</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> .env</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> commit</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -m</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> \"Stop tracking .env\"</span></span></code></pre></div>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><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\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">Common mistake</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Ignoring a secret after pushing it</span></p>\n<p>If <code dir=\"ltr\">.env</code> with an API key was pushed even once, it’s in the repository’s history and in every clone, and adding it to <code dir=\"ltr\">.gitignore</code> changes none of that. Treat the key as leaked: revoke it with the provider and issue a new one. Then untrack the file. GitHub’s push protection blocks many known secret formats at push time, but it’s a safety net, not a plan; write <code dir=\"ltr\">.gitignore</code> before the first commit.</p>\n</aside>\n<p>Your working tree is now clean and your repository holds only what it should. Next you’ll make what it holds readable: commit messages, tags and releases.</p>\n","toc":[{"id":"sec-1","text":"Stash: a drawer for unfinished work","level":2},{"id":"sec-2","text":".gitignore: files Git should never track","level":2},{"id":"sec-3","text":"How patterns work","level":2},{"id":"sec-4","text":"Ignoring doesn’t untrack","level":2}],"takeaways":["<code dir=\"ltr\">git stash push -m &quot;…&quot;</code> saves your uncommitted changes and cleans the working tree; <code dir=\"ltr\">git stash pop</code> brings them back and removes the stash.","<code dir=\"ltr\">git stash</code> skips untracked files unless you add <code dir=\"ltr\">-u</code> (<code dir=\"ltr\">--include-untracked</code>).","<code dir=\"ltr\">.gitignore</code> only affects untracked files; to stop tracking a committed file, run <code dir=\"ltr\">git rm --cached</code> and commit.","In <code dir=\"ltr\">.gitignore</code>, a trailing <code dir=\"ltr\">/</code> matches directories only, a leading <code dir=\"ltr\">/</code> anchors to that folder, and <code dir=\"ltr\">!</code> re-includes a file.","A secret that was ever committed and pushed must be revoked and replaced, because history still contains it."],"further":[{"title":"git stash reference","url":"https://git-scm.com/docs/git-stash"},{"title":"gitignore pattern format","url":"https://git-scm.com/docs/gitignore"},{"title":"Ignoring files (GitHub Docs)","url":"https://docs.github.com/en/get-started/git-basics/ignoring-files"}],"quiz":[{"q":"<p>You’re halfway through the contact form when an urgent typo fix is needed on <code dir=\"ltr\">main</code>. <code dir=\"ltr\">git switch main</code> refuses because it would overwrite your changes. What’s the quickest clean route?</p>","options":[{"text":"Delete your changes with <code dir=\"ltr\">git restore .</code>, fix the typo, and redo the form later.","why":"That throws away real work to save a few seconds. Stash keeps it safely."},{"text":"<code dir=\"ltr\">git stash push -m &quot;contact form wip&quot;</code>, switch to <code dir=\"ltr\">main</code>, fix and commit, switch back, <code dir=\"ltr\">git stash pop</code>.","why":"Correct. The stash holds your half-done work while the working tree is clean, and pop brings it back where you left off."},{"text":"Force the switch with <code dir=\"ltr\">git switch -f main</code>.","why":"<code dir=\"ltr\">-f</code> throws away your local changes to make the switch, exactly what you wanted to avoid."},{"text":"Commit the half-finished form to <code dir=\"ltr\">main</code> with the message “WIP”.","why":"You’d be putting broken work on <code dir=\"ltr\">main</code>. If you want a WIP commit, make it on your feature branch."}],"answer":1},{"q":"<p>You stashed, switched branches, and came back. <code dir=\"ltr\">git stash pop</code> restored your edits to <code dir=\"ltr\">contact.html</code> but your new file <code dir=\"ltr\">contact.js</code> is missing. Why?</p>","options":[{"text":"<code dir=\"ltr\">git stash pop</code> restores files in the order they were edited and stopped early.","why":"Pop restores everything in the stash at once. The file was never in the stash."},{"text":"The file was deleted by switching branches.","why":"Switching leaves untracked files alone. It was the stash that skipped it, which is why it may still be in your folder."},{"text":"Stashes expire after one branch switch.","why":"Stashes stay until you drop or pop them. <code dir=\"ltr\">git stash list</code> shows them."},{"text":"<code dir=\"ltr\">git stash</code> doesn’t include untracked files unless you pass <code dir=\"ltr\">-u</code>, so <code dir=\"ltr\">contact.js</code> was left behind in the working tree.","why":"Correct. Untracked files aren’t stashed by default. Check the working tree, it’s probably there, and use <code dir=\"ltr\">git stash -u</code> next time."}],"answer":3},{"q":"<p>You committed <code dir=\"ltr\">.env</code> last week. Today you add <code dir=\"ltr\">.env</code> to <code dir=\"ltr\">.gitignore</code>, but <code dir=\"ltr\">git status</code> still shows <code dir=\"ltr\">.env</code> as modified. Why?</p>","options":[{"text":"<code dir=\"ltr\">.gitignore</code> only applies to untracked files, and <code dir=\"ltr\">.env</code> is already tracked; run <code dir=\"ltr\">git rm --cached .env</code> and commit.","why":"Correct. <code dir=\"ltr\">--cached</code> removes it from the index (so future commits don’t include it) while leaving the file on disk."},{"text":"The pattern needs to be <code dir=\"ltr\">/.env/</code> to work.","why":"A trailing slash makes a pattern match only directories, so <code dir=\"ltr\">/.env/</code> wouldn’t match the file at all."},{"text":"<code dir=\"ltr\">.gitignore</code> changes take effect only after a push.","why":"Ignore rules apply immediately, locally. The problem is that tracked files are never ignored."}],"answer":0},{"q":"<p>Which <code dir=\"ltr\">.gitignore</code> line ignores the <code dir=\"ltr\">dist</code> folder at the project root but not a <code dir=\"ltr\">src/dist/</code> folder?</p>","options":[{"text":"<code dir=\"ltr\">dist</code>","why":"Without a slash at the start or middle, the pattern matches <code dir=\"ltr\">dist</code> at any depth, including <code dir=\"ltr\">src/dist</code>."},{"text":"<code dir=\"ltr\">**/dist/</code>","why":"<code dir=\"ltr\">**/</code> means at any depth, so this also matches <code dir=\"ltr\">src/dist/</code>."},{"text":"<code dir=\"ltr\">/dist/</code>","why":"Correct. The leading slash anchors the pattern to the folder containing the <code dir=\"ltr\">.gitignore</code>, and the trailing slash limits it to directories."},{"text":"<code dir=\"ltr\">!dist</code>","why":"<code dir=\"ltr\">!</code> re-includes a previously ignored path; on its own it ignores nothing."}],"answer":2}],"exercise":{"kind":"spot-bug","language":"text","code":"# Dependencies\nnode_modules/\n\n# Build output from the Sass experiment\n*.css\n\n# Local environment (never commit secrets)\n.env\nsecrets.json   # API keys\n!.env.example\n\n# OS and editor files\n/.DS_Store\n.vscode/\n*.log","bugLines":[5,9,13],"title":"Fix the portfolio's .gitignore","prompt":"<p>This <code dir=\"ltr\">.gitignore</code> sits at the root of the portfolio repository, which contains <code dir=\"ltr\">index.html</code>, <code dir=\"ltr\">styles.css</code>, <code dir=\"ltr\">projects.html</code>, a <code dir=\"ltr\">.env</code> with an API key, <code dir=\"ltr\">secrets.json</code>, and macOS <code dir=\"ltr\">.DS_Store</code> files in several folders. Three lines don’t do what their author intended. Select them.</p>\n","hints":["One pattern hides a file the site needs to work.","Comments in <code dir=\"ltr\">.gitignore</code> only work in one position on a line.","<code dir=\"ltr\">.DS_Store</code> files appear in every folder macOS has opened, not only the root."],"explanation":"<p>Line 5, <code dir=\"ltr\">*.css</code>, ignores every CSS file, including your hand-written <code dir=\"ltr\">styles.css</code>; ignore only the real build output folder instead (for example <code dir=\"ltr\">/dist/</code>). Line 9 has a trailing comment, but <code dir=\"ltr\">#</code> starts a comment only at the beginning of a line, so the pattern is the literal text <code dir=\"ltr\">secrets.json   # API keys</code> and <code dir=\"ltr\">secrets.json</code> is not ignored; move the comment to its own line. Line 13, <code dir=\"ltr\">/.DS_Store</code>, is anchored to the root, so <code dir=\"ltr\">.DS_Store</code> files in subfolders still show up; drop the leading slash (<code dir=\"ltr\">.DS_Store</code>), or better, put it in your global ignore file. The <code dir=\"ltr\">!.env.example</code> line is fine: it keeps the template file other developers need.</p>\n","checkLabels":{}},"words":749,"readMinutes":4}