{"course":{"slug":"building-apps-with-ai","title":"Building Apps with AI","url":"https://addaly.com/learn/building-apps-with-ai","level":"beginner","track":"build"},"lesson":{"slug":"what-a-commit-actually-is","title":"What a commit actually is","url":"https://addaly.com/learn/building-apps-with-ai/what-a-commit-actually-is","position":38,"of":87,"minutes":8,"answer":"A commit is a snapshot of whatever you staged, not a list of edits, so staging is where you decide which of today's changes belong together.","keyIdea":"A commit is a snapshot of whatever you staged, not a list of edits, so staging is where you decide which of today's changes belong together."},"body":{"format":"markdown","text":"## Three places, not one\n\nWhen you edit a file, git is looking at three versions of your project at once.\n\nThe **working tree** is the folder you can see. The **staging area** (git also calls it the index) is a draft of the next save point. The **repository** is the chain of commits already made.\n\n`git add` copies a change from the working tree into the draft. `git commit` turns the draft into a permanent commit. The first git lesson had you run `git add -A` and skip the middle step, which is fine until the day the folder holds two unrelated changes and you want to save one without the other. That day arrives quickly when an agent is doing the editing, because agents rarely make one change at a time.\n\n## A commit is a photograph, not a list of edits\n\nThis is the idea that makes the rest of git make sense. A commit does not store \"line 14 changed from X to Y\". It stores a complete snapshot of every tracked file as it was at that moment, plus a pointer to the commit before it. The red and green diff you see is computed afterwards, by comparing two snapshots.\n\nThree things follow from that.\n\nThe id (`a3f9c21`) is the first seven characters of a hash of the snapshot's contents, its parent and its message. Identical content produces an identical id; change one byte anywhere and the id changes. So a commit cannot be edited. `git commit --amend` does not alter the last commit, it makes a new one with a new id and quietly abandons the old one.\n\nFiles that did not change between commits are stored once, not copied. A thousand commits of a project are usually only slightly larger than the project itself.\n\nAnd a commit has no idea which lines you \"meant\". It holds whatever was staged. The meaning lives in your choice of what to stage together.\n\n## Staging part of a change\n\n```bash\ngit add src/booking.ts          # stage one file\ngit add -p                      # walk through each change and say y or n\ngit diff                        # working tree versus staging\ngit diff --staged               # staging versus the last commit\n```\n\n`git add -p` shows you each hunk of change and asks. `y` stages it, `n` skips it, `s` splits a large hunk into smaller ones. It takes a minute to get used to and it is the tool for the situation above: stage the fix, commit it with a message that says what is now true, and leave the reformatting for a separate decision.\n\nRead `git diff --staged` before every commit. It is exactly what the commit will contain, no more and no less. `git diff` on its own is not: it shows what is not yet staged.\n\n## What git does and does not track\n\nGit tracks the contents of files. It does not track folders: an empty folder is invisible to it, which is why some projects carry an empty `.gitkeep` file inside directories they need to exist. It does not track timestamps, and it tracks the executable bit but no other permissions.\n\nIt does not record renames. Moving a file shows up as a deletion and an addition, and git guesses afterwards, from similarity of content, that the two were one file. Rename and heavily edit a file in the same commit and the guess fails; the history of that file appears to start from nothing.\n\nLine endings are the trap for anyone on Windows. Windows ends lines with two characters, everything else with one. Open a file in the wrong editor and every line changes, and `git diff` reports that you rewrote a 400-line file when you touched one line. A committed `.gitattributes` containing `* text=auto` tells git to normalise, and it is worth adding on day one because the fix is harder after the fact.\n\n## Large files live forever\n\nA 40 MB screen recording committed once stays in the history permanently. Every clone downloads it, even after you delete the file, because the snapshot that contained it still exists. GitHub refuses individual files over 100 MB outright.\n\nSo `.gitignore` is not only for secrets. Build output (`.next`, `dist`, `build`), `node_modules`, uploaded images, exports and logs all belong in it. The test: if a file can be regenerated from other files, or was produced by a user rather than by you, it does not belong in the repository.\n\n## Reading `git status`\n\nIts output has three sections, in a fixed order: **changes to be committed** (staged), **changes not staged** (edited but not yet added), and **untracked files** (new, never added). The line you want at the end of a session is `nothing to commit, working tree clean`: the folder is exactly the last commit, and tomorrow starts from a known state.\n\nRun it before an agent starts and after it finishes. The difference between the two is the agent's whole day, and it should match what you asked for."},"check":{"question":"You ask an agent to fix a date bug. The diff shows the fix in one file and formatting changes across six others. You want a save point that contains only the fix. What do you do?","options":[{"text":"Run git add -A and git commit, and mention the formatting changes in the commit message so the history explains them.","correct":false,"tempting":"A commit is a snapshot of everything staged; the message does not separate the two changes, and reverting the fix later would revert the formatting with it."},{"text":"Stage only the one file, or the relevant hunks with git add -p, commit, then decide about the rest.","correct":true},{"text":"Ask the agent to undo the formatting and apply the fix again.","correct":false,"tempting":"Discards a step git already gives you, and a second run is not guaranteed to reproduce the same fix."},{"text":"Commit everything, then git revert the formatting part.","correct":false,"tempting":"Revert undoes a whole commit; it cannot undo part of one, which is exactly why the split has to happen before the commit."}]},"prev":{"slug":"git-when-you-have-never-used-it","title":"Save points: git when you have never used it","url":"https://addaly.com/learn/building-apps-with-ai/git-when-you-have-never-used-it"},"next":{"slug":"three-ways-back","title":"Three ways back, and the undo for undo","url":"https://addaly.com/learn/building-apps-with-ai/three-ways-back"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'What a commit actually is', in Building Apps with AI. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/building-apps-with-ai/what-a-commit-actually-is (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"What a commit actually is","courseTitle":"Building Apps with AI","module":{"index":5,"slug":"save-points-and-shipping","title":"Save points, and shipping to a stranger"},"answer":null,"keyIdea":"A commit is a snapshot of whatever you staged, not a list of edits, so staging is where you decide which of today’s changes belong together.","hero":{"kind":"plate","image":null,"alt":null,"caption":null},"blocks":[{"t":"h2","id":"three-places-not-one","runs":[{"text":"Three places, not one"}]},{"t":"p","runs":[{"text":"When you edit a file, git is looking at three versions of your project at once."}]},{"t":"p","runs":[{"text":"The "},{"text":"working tree","b":true},{"text":" is the folder you can see. The "},{"text":"staging area","b":true},{"text":" (git also calls it the index) is a draft of the next save point. The "},{"text":"repository","b":true},{"text":" is the chain of commits already made."}]},{"t":"p","runs":[{"text":"git add","code":true},{"text":" copies a change from the working tree into the draft. "},{"text":"git commit","code":true},{"text":" turns the draft into a permanent commit. The first git lesson had you run "},{"text":"git add -A","code":true},{"text":" and skip the middle step, which is fine until the day the folder holds two unrelated changes and you want to save one without the other. That day arrives quickly when an agent is doing the editing, because agents rarely make one change at a time."}]},{"t":"h2","id":"a-commit-is-a-photograph-not-a-list-of-edits","runs":[{"text":"A commit is a photograph, not a list of edits"}]},{"t":"p","runs":[{"text":"This is the idea that makes the rest of git make sense. A commit does not store “line 14 changed from X to Y”. It stores a complete snapshot of every tracked file as it was at that moment, plus a pointer to the commit before it. The red and green diff you see is computed afterwards, by comparing two snapshots."}]},{"t":"p","runs":[{"text":"Three things follow from that."}]},{"t":"p","runs":[{"text":"The id ("},{"text":"a3f9c21","code":true},{"text":") is the first seven characters of a hash of the snapshot’s contents, its parent and its message. Identical content produces an identical id; change one byte anywhere and the id changes. So a commit cannot be edited. "},{"text":"git commit --amend","code":true},{"text":" does not alter the last commit, it makes a new one with a new id and quietly abandons the old one."}]},{"t":"p","runs":[{"text":"Files that did not change between commits are stored once, not copied. A thousand commits of a project are usually only slightly larger than the project itself."}]},{"t":"p","runs":[{"text":"And a commit has no idea which lines you “meant”. It holds whatever was staged. The meaning lives in your choice of what to stage together."}]},{"t":"h2","id":"staging-part-of-a-change","runs":[{"text":"Staging part of a change"}]},{"t":"code","lang":"bash","label":"Bash","text":"git add src/booking.ts          # stage one file\ngit add -p                      # walk through each change and say y or n\ngit diff                        # working tree versus staging\ngit diff --staged               # staging versus the last commit"},{"t":"p","runs":[{"text":"git add -p","code":true},{"text":" shows you each hunk of change and asks. "},{"text":"y","code":true},{"text":" stages it, "},{"text":"n","code":true},{"text":" skips it, "},{"text":"s","code":true},{"text":" splits a large hunk into smaller ones. It takes a minute to get used to and it is the tool for the situation above: stage the fix, commit it with a message that says what is now true, and leave the reformatting for a separate decision."}]},{"t":"p","runs":[{"text":"Read "},{"text":"git diff --staged","code":true},{"text":" before every commit. It is exactly what the commit will contain, no more and no less. "},{"text":"git diff","code":true},{"text":" on its own is not: it shows what is not yet staged."}]},{"t":"h2","id":"what-git-does-and-does-not-track","runs":[{"text":"What git does and does not track"}]},{"t":"p","runs":[{"text":"Git tracks the contents of files. It does not track folders: an empty folder is invisible to it, which is why some projects carry an empty "},{"text":".gitkeep","code":true},{"text":" file inside directories they need to exist. It does not track timestamps, and it tracks the executable bit but no other permissions."}]},{"t":"p","runs":[{"text":"It does not record renames. Moving a file shows up as a deletion and an addition, and git guesses afterwards, from similarity of content, that the two were one file. Rename and heavily edit a file in the same commit and the guess fails; the history of that file appears to start from nothing."}]},{"t":"p","runs":[{"text":"Line endings are the trap for anyone on Windows. Windows ends lines with two characters, everything else with one. Open a file in the wrong editor and every line changes, and "},{"text":"git diff","code":true},{"text":" reports that you rewrote a 400-line file when you touched one line. A committed "},{"text":".gitattributes","code":true},{"text":" containing "},{"text":"* text=auto","code":true},{"text":" tells git to normalise, and it is worth adding on day one because the fix is harder after the fact."}]},{"t":"h2","id":"large-files-live-forever","runs":[{"text":"Large files live forever"}]},{"t":"p","runs":[{"text":"A 40 MB screen recording committed once stays in the history permanently. Every clone downloads it, even after you delete the file, because the snapshot that contained it still exists. GitHub refuses individual files over 100 MB outright."}]},{"t":"p","runs":[{"text":"So "},{"text":".gitignore","code":true},{"text":" is not only for secrets. Build output ("},{"text":".next","code":true},{"text":", "},{"text":"dist","code":true},{"text":", "},{"text":"build","code":true},{"text":"), "},{"text":"node_modules","code":true},{"text":", uploaded images, exports and logs all belong in it. The test: if a file can be regenerated from other files, or was produced by a user rather than by you, it does not belong in the repository."}]},{"t":"h2","id":"reading-git-status","runs":[{"text":"Reading "},{"text":"git status","code":true}]},{"t":"p","runs":[{"text":"Its output has three sections, in a fixed order: "},{"text":"changes to be committed","b":true},{"text":" (staged), "},{"text":"changes not staged","b":true},{"text":" (edited but not yet added), and "},{"text":"untracked files","b":true},{"text":" (new, never added). The line you want at the end of a session is "},{"text":"nothing to commit, working tree clean","code":true},{"text":": the folder is exactly the last commit, and tomorrow starts from a known state."}]},{"t":"p","runs":[{"text":"Run it before an agent starts and after it finishes. The difference between the two is the agent’s whole day, and it should match what you asked for."}]}],"check":{"question":[{"text":"You ask an agent to fix a date bug. The diff shows the fix in one file and formatting changes across six others. You want a save point that contains only the fix. What do you do?"}],"options":[{"text":[{"text":"Run git add -A and git commit, and mention the formatting changes in the commit message so the history explains them."}],"correct":false,"tempting":[{"text":"A commit is a snapshot of everything staged; the message does not separate the two changes, and reverting the fix later would revert the formatting with it."}]},{"text":[{"text":"Stage only the one file, or the relevant hunks with git add -p, commit, then decide about the rest."}],"correct":true,"tempting":null},{"text":[{"text":"Ask the agent to undo the formatting and apply the fix again."}],"correct":false,"tempting":[{"text":"Discards a step git already gives you, and a second run is not guaranteed to reproduce the same fix."}]},{"text":[{"text":"Commit everything, then git revert the formatting part."}],"correct":false,"tempting":[{"text":"Revert undoes a whole commit; it cannot undo part of one, which is exactly why the split has to happen before the commit."}]}],"order":[3,0,2,1],"why":null},"prev":{"slug":"git-when-you-have-never-used-it","title":"Save points: git when you have never used it","minutes":9},"next":{"slug":"three-ways-back","title":"Three ways back, and the undo for undo","minutes":9}}}