{"id":"l-git-1-3","courseId":"git-github","lang":"en","kind":"lesson","summary":"Move changes deliberately between the working tree, the staging area and the repository, check each step with status and diff, and split messy work into focused commits.","html":"<p>You spent an evening on the portfolio. You added a navigation bar to <code dir=\"ltr\">index.html</code>, created <code dir=\"ltr\">styles.css</code>, and fixed a typo in your name along the way. That’s three unrelated changes. If you commit them together as “updates”, future you can’t undo the nav without also undoing the typo fix. Git gives you a place to sort changes before they become history.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">Three places your work can be</h2>\n<p>Every change in a Git project lives in one of three places:</p>\n<ul>\n<li>The <strong>working tree</strong> is the files on disk, the ones your editor opens. You can change them freely; Git only watches.</li>\n<li>The <strong>index</strong>, also called the <strong>staging area</strong>, is the next commit being assembled. <code dir=\"ltr\">git add</code> copies a file’s current content into it.</li>\n<li>The <strong>repository</strong> is the commits already recorded, inside <code dir=\"ltr\">.git</code>. <code dir=\"ltr\">git commit</code> turns the index into a new commit.</li>\n</ul>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 700 270\" role=\"img\" aria-labelledby=\"l-git-1-3-t1\"><defs><marker id=\"arrow-l-git-1-3-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-git-1-3-t1\">Three boxes left to right: working tree, index (staging area), repository. git add moves from working tree to index, git commit from index to repository. Below, git restore --staged moves from repository back to the index, and git restore moves from index back to the working tree.</title>\n  <rect class=\"d-box\" x=\"20\" y=\"70\" width=\"180\" height=\"80\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"110\" y=\"105\" text-anchor=\"middle\">Working tree</text>\n  <text class=\"d-label-muted\" x=\"110\" y=\"128\" text-anchor=\"middle\">files on disk</text>\n  <rect class=\"d-box-accent\" x=\"260\" y=\"70\" width=\"180\" height=\"80\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"350\" y=\"105\" text-anchor=\"middle\">Index</text>\n  <text class=\"d-label-muted\" x=\"350\" y=\"128\" text-anchor=\"middle\">next commit</text>\n  <rect class=\"d-box-primary\" x=\"500\" y=\"70\" width=\"180\" height=\"80\" rx=\"12\"/>\n  <text class=\"d-label-strong\" x=\"590\" y=\"105\" text-anchor=\"middle\">Repository</text>\n  <text class=\"d-label-muted\" x=\"590\" y=\"128\" text-anchor=\"middle\">recorded commits</text>\n  <path class=\"d-arrow\" d=\"M200 90 L256 90\" marker-end=\"url(#arrow-l-git-1-3-1)\"/>\n  <text class=\"d-code\" x=\"228\" y=\"55\" text-anchor=\"middle\">git add</text>\n  <path class=\"d-arrow\" d=\"M440 90 L496 90\" marker-end=\"url(#arrow-l-git-1-3-1)\"/>\n  <text class=\"d-code\" x=\"468\" y=\"55\" text-anchor=\"middle\">git commit</text>\n  <path class=\"d-arrow d-dashed\" d=\"M500 140 C470 210 420 210 400 154\" marker-end=\"url(#arrow-l-git-1-3-1)\"/>\n  <text class=\"d-code\" x=\"470\" y=\"230\" text-anchor=\"middle\">git restore --staged</text>\n  <path class=\"d-arrow d-dashed\" d=\"M260 140 C230 210 180 210 160 154\" marker-end=\"url(#arrow-l-git-1-3-1)\"/>\n  <text class=\"d-code\" x=\"200\" y=\"230\" text-anchor=\"middle\">git restore</text>\n  <text class=\"d-label-muted\" x=\"350\" y=\"262\" text-anchor=\"middle\">Dashed: copying back. git restore overwrites your file.</text>\n</svg><figcaption>Commands move content between the three areas</figcaption></figure>\n<p>After a commit, the index isn’t emptied. It still holds the full snapshot you just committed, so it matches the last commit until you stage something new. That’s why “staged changes” means the difference between the index and the last commit.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\">Seeing the difference: status and two diffs</h2>\n<p>Here’s the evening’s work, checked with <code dir=\"ltr\">git status</code>:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"0\"><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>On branch main\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n\tmodified:   index.html\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n\tstyles.css\n\nno changes added to commit (use &quot;git add&quot; and/or &quot;git commit -a&quot;)</code></pre></div>\n<p><code dir=\"ltr\">git status</code> tells you which files differ. To see the lines, use <code dir=\"ltr\">git diff</code>, and remember there are two comparisons:</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\"> diff</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">            # working tree vs index: what you haven't staged yet</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> diff</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --staged</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">   # index vs last commit: what the next commit will contain</span></span></code></pre></div>\n<p><code dir=\"ltr\">--cached</code> is an older synonym for <code dir=\"ltr\">--staged</code>; you’ll see both in tutorials. Get into the habit of running <code dir=\"ltr\">git diff --staged</code> right before every commit. It’s the last moment to notice a stray <code dir=\"ltr\">console.log</code> or a file that doesn’t belong.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">Splitting one file into two commits</h2>\n<p>The typo fix and the nav bar are both in <code dir=\"ltr\">index.html</code>. <code dir=\"ltr\">git add index.html</code> would stage both. Stage just the typo instead:</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\"> add</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> -p</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> index.html</span></span></code></pre></div>\n<p>Git shows each changed block, called a hunk, and asks <code dir=\"ltr\">Stage this hunk [y,n,q,a,d,s,e,?]?</code> (newer versions list a few more letters; <code dir=\"ltr\">?</code> explains them all). Answer <code dir=\"ltr\">y</code> for the typo hunk and <code dir=\"ltr\">n</code> for the nav hunk (<code dir=\"ltr\">s</code> splits a hunk that’s too big). Then:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"bash\" data-index=\"3\"><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\"> diff</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> --staged</span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">          # only the typo fix</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\"> \"Fix spelling of name in header\"</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">git</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> add</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> index.html</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> styles.css</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\"> \"Add navigation bar with base styles\"</span></span></code></pre></div>\n<p>Two commits, each with one purpose. Later, if the nav bar needs to go, you can undo that commit alone.</p>\n<h2 id=\"sec-4\" tabindex=\"-1\">How big should a commit be?</h2>\n<p>A good commit does one thing you could describe in a short sentence without the word “and”. “Fix spelling of name in header” passes. “Add nav, fix typo, tweak colours” fails, and the failure shows up later: when the colours turn out wrong, undoing that commit also removes the nav and brings back the typo.</p>\n<p>There’s no line limit. A commit that renames a CSS class across twelve files is still one idea, and splitting it would leave the site broken in between. Aim for commits where the project still works before and after, each one a step you could explain to a reviewer in one breath. You’ll appreciate this in section 4, when undoing a single commit becomes a one-line command instead of an afternoon of surgery.</p>\n<aside class=\"callout callout-note\" 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\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/></svg><span><span class=\"callout-kind\">Note</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>Why Git has a staging area at all</span></p>\n<p>Some version control systems commit every changed file at once. Git’s index exists so that what you <em>did</em> (an evening of mixed edits) and what you <em>record</em> (clean, single-purpose steps) can be different. You don’t have to use it cleverly every time, but it’s there when your work gets messy.</p>\n</aside>\n<h2 id=\"sec-5\" tabindex=\"-1\">Short status, and backing out</h2>\n<p><code dir=\"ltr\">git status -s</code> packs the same information into two columns: the left is the index versus the last commit, the right is the working tree versus the index.</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"text\" data-index=\"4\"><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>M  README.md\n M index.html\nMM styles.css\n?? projects.html</code></pre></div>\n<p><code dir=\"ltr\">README.md</code> is staged; <code dir=\"ltr\">index.html</code> has unstaged changes; <code dir=\"ltr\">styles.css</code> has some of each; <code dir=\"ltr\">projects.html</code> is untracked.</p>\n<p>To take a file out of the index without losing your edits, use <code dir=\"ltr\">git restore --staged styles.css</code>. To throw away unstaged edits and go back to the index version, use <code dir=\"ltr\">git restore styles.css</code>. The second one is the only command in this lesson that destroys work: changes that were never staged or committed can’t be recovered.</p>\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>Trusting git commit -a with new files</span></p>\n<p><code dir=\"ltr\">git commit -am &quot;Add projects page&quot;</code> stages every <em>modified tracked</em> file and commits. A brand-new <code dir=\"ltr\">projects.html</code> is untracked, so it’s silently left out and the message lies. Use <code dir=\"ltr\">-a</code> only when <code dir=\"ltr\">git status</code> shows no untracked files you care about, or run <code dir=\"ltr\">git add</code> for new files first.</p>\n</aside>\n<p>You can now record exactly the history you mean to. Next you’ll read that history back, and see why Git calls it a graph rather than a list.</p>\n","toc":[{"id":"sec-1","text":"Three places your work can be","level":2},{"id":"sec-2","text":"Seeing the difference: status and two diffs","level":2},{"id":"sec-3","text":"Splitting one file into two commits","level":2},{"id":"sec-4","text":"How big should a commit be?","level":2},{"id":"sec-5","text":"Short status, and backing out","level":2}],"takeaways":["The working tree is your files, the index (staging area) is the next commit being assembled, and the repository is the commits already recorded.","<code dir=\"ltr\">git diff</code> compares the working tree to the index; <code dir=\"ltr\">git diff --staged</code> compares the index to the last commit.","<code dir=\"ltr\">git add -p</code> stages part of a file, so one messy editing session can become several focused commits.","<code dir=\"ltr\">git restore --staged &lt;file&gt;</code> unstages and keeps your edits; <code dir=\"ltr\">git restore &lt;file&gt;</code> throws your unstaged edits away.","<code dir=\"ltr\">git commit -a</code> stages modified tracked files only; brand-new files still need <code dir=\"ltr\">git add</code>."],"further":[{"title":"Recording Changes to the Repository (Pro Git)","url":"https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository"},{"title":"git restore reference","url":"https://git-scm.com/docs/git-restore"},{"title":"git add reference","url":"https://git-scm.com/docs/git-add"}],"quiz":[{"q":"<p>You staged <code dir=\"ltr\">index.html</code>, then edited it again. <code dir=\"ltr\">git diff</code> shows only the second edit. Why?</p>","options":[{"text":"Git lost the first edit when you saved the file again.","why":"Nothing is lost. The first edit is safely in the index; <code dir=\"ltr\">git diff --staged</code> would show it."},{"text":"<code dir=\"ltr\">git diff</code> only shows the most recent save of each file.","why":"Git doesn’t track saves. It compares two whole states, and which two depends on the command."},{"text":"<code dir=\"ltr\">git diff</code> compares the working tree to the index, and the first edit is already in the index.","why":"Correct. With the first edit staged, the only difference left between the file on disk and the index is the second edit."},{"text":"The second <code dir=\"ltr\">add</code> is required before <code dir=\"ltr\">git diff</code> shows anything.","why":"<code dir=\"ltr\">git diff</code> shows unstaged changes, which is exactly what the second edit is. Staging it would make <code dir=\"ltr\">git diff</code> show nothing."}],"answer":2},{"q":"<p>You ran <code dir=\"ltr\">git add styles.css</code> but want it in the next commit after all, not this one. Which command keeps your edits and only unstages the file?</p>","options":[{"text":"<code dir=\"ltr\">git restore --staged styles.css</code>","why":"Correct. It copies the last committed version into the index, so the file is unstaged while your edits stay in the working tree."},{"text":"<code dir=\"ltr\">git restore styles.css</code>","why":"Without <code dir=\"ltr\">--staged</code> this targets the working tree and replaces your file with the index version. Your edits would be gone."},{"text":"<code dir=\"ltr\">git rm styles.css</code>","why":"This stages the file’s deletion and removes it from disk. That’s the opposite of what you want."},{"text":"<code dir=\"ltr\">git commit --skip styles.css</code>","why":"There’s no <code dir=\"ltr\">--skip</code> option on <code dir=\"ltr\">git commit</code>. Unstaging happens in the index before you commit."}],"answer":0},{"q":"<p>You created <code dir=\"ltr\">projects.html</code> and edited <code dir=\"ltr\">index.html</code>, then ran <code dir=\"ltr\">git commit -am &quot;Add projects page&quot;</code>. What did the commit contain?</p>","options":[{"text":"Both files, because <code dir=\"ltr\">-a</code> means all files in the folder.","why":"<code dir=\"ltr\">-a</code> means all modified tracked files. A file Git has never tracked isn’t included."},{"text":"Nothing, because <code dir=\"ltr\">-a</code> can’t be combined with <code dir=\"ltr\">-m</code>.","why":"<code dir=\"ltr\">-am</code> is a common and valid combination: stage tracked changes, then commit with this message."},{"text":"Only <code dir=\"ltr\">projects.html</code>, because it’s the newer file.","why":"The age of a file doesn’t matter to Git. What matters is whether it’s tracked."},{"text":"Only the <code dir=\"ltr\">index.html</code> changes; <code dir=\"ltr\">projects.html</code> is still untracked.","why":"Correct. <code dir=\"ltr\">-a</code> skips untracked files, which is why the commit message now describes a page that isn’t in the commit."}],"answer":3},{"q":"<p>In <code dir=\"ltr\">git status -s</code>, what does the line <code dir=\"ltr\">MM index.html</code> tell you?</p>","options":[{"text":"The file was modified twice since the last commit.","why":"Git doesn’t count edits. The two columns describe two different comparisons."},{"text":"Some changes to the file are staged and other changes to it are not.","why":"Correct. The left column is the index versus the last commit, the right column is the working tree versus the index; both say modified."},{"text":"The file has a merge conflict.","why":"Conflicts show up as <code dir=\"ltr\">UU</code> (unmerged) in short status, not <code dir=\"ltr\">MM</code>."}],"answer":1}],"exercise":{"kind":"fill","language":"bash","template":"git status\ngit add {{0}} index.html     # stage only the typo-fix hunk\ngit diff {{1}}               # check what the next commit contains\ngit commit -m \"Fix spelling of name in header\"\n\ngit add index.html styles.css\ngit restore {{2}} styles.css   # oops: unstage it, keep the edits\ngit commit -m \"Add navigation bar\"","blanks":[{"answers":["-p","--patch"]},{"answers":["--staged","--cached"]},{"answers":["--staged","-S"]}],"title":"Stage on purpose","prompt":"<p>Complete the session. You stage only part of <code dir=\"ltr\">index.html</code> (the typo fix), check exactly what will be committed, commit it, then stage the nav work but take <code dir=\"ltr\">styles.css</code> back out of the index without losing your edits.</p>\n","hints":["Partial staging works hunk by hunk. The flag is short for patch.","Plain <code dir=\"ltr\">git diff</code> shows unstaged changes. The flag you need compares the index with the last commit.","The same <code dir=\"ltr\">git restore</code> command can either discard edits or unstage. Only one of those is safe here."],"explanation":"<p><code dir=\"ltr\">git add -p</code> walks through each hunk so you can stage the typo fix alone. <code dir=\"ltr\">git diff --staged</code> (or <code dir=\"ltr\">--cached</code>) shows the index against the last commit, which is exactly the next commit. <code dir=\"ltr\">git restore --staged styles.css</code> copies the committed version into the index, unstaging the file while your edits stay in the working tree. Without <code dir=\"ltr\">--staged</code>, <code dir=\"ltr\">git restore</code> would have overwritten your file.</p>\n","checkLabels":{}},"words":747,"readMinutes":4}