SECTION 1
Historical Context & Motivation
Imagine writing a ten-page essay and accidentally deleting three pages with no way to get them back. Before version control systems existed, programmers faced exactly that risk every day. Early developers would copy entire folders of code and rename them with dates like project_backup_March5, which quickly became a chaotic mess. The need for a reliable way to track changes, undo mistakes, and collaborate with teammates drove the creation of increasingly sophisticated tools.
1972 • SCCS — Source Code Control System
1986 • CVS — Concurrent Versions System
2000 • Subversion (SVN)
2005 • Git Created by Linus Torvalds
2008 • GitHub Launches
Today, Git is the most widely used version control system in the world, and the commit is its fundamental building block. But what exactly is a commit, how does it capture your work, and why does writing a good commit message matter so much? Those are the questions this lesson will answer.
SECTION 2
Core Principles & Definitions
A Git commit is a permanent snapshot of your project at a specific moment in time. Think of it like pressing the save button in a video game — it records exactly where everything stands so you can return to that point later. Each commit also carries a commit message, a short description written by the developer that explains what changed and why. Understanding a few foundational ideas will make the entire commit workflow click.
Repository (Repo)
.git directory where Git stores the full history of every change ever made.Working Directory
Staging Area (Index)
Commit (Snapshot)
Commit Message
KEY TAKEAWAY
SECTION 3
Visual Explanation — The Commit Workflow
The diagram below shows the three zones that every file passes through on its way to becoming part of a commit. Understanding this flow is the single most important concept in using Git effectively.
git add into the staging area, and permanently saved to the repository via git commit. Each commit receives a unique hash ID and the developer's commit message.Notice that readme.md was modified in the working directory but was not staged. This is intentional — Git lets you be selective about which changes go into each commit. You might fix a bug in one file and start a new feature in another; by staging only the bug fix, you keep each commit focused on a single purpose. This practice, called making atomic commits, makes your project history much easier to read and debug.
SECTION 4
How a Commit Works Under the Hood
When you run git commit -m "Your message", Git performs several steps behind the scenes. Understanding this mechanism helps you appreciate why commits are so reliable and why the commit message is important metadata, not just a formality.
Anatomy of a Commit Object
Every commit is stored as a commit object inside the hidden .git folder. This object contains four pieces of information: a pointer to a tree (which records the state of every file at that moment), a pointer to the parent commit (the snapshot that came right before), the author and timestamp, and the commit message. Git generates a unique 40-character SHA-1 hash (like a3f7c2d...) from this content, which acts as the commit's fingerprint.
The Commit Commands in Sequence
Here is the typical command sequence you would type in a terminal. First, git status shows which files have been modified. Next, git add <filename> (or git add . for all changed files) moves them to the staging area. Finally, git commit -m "Fix login validation bug" creates the permanent snapshot with your message. After this, git log lets you view the chain of commits, each with its hash, author, date, and message.
The -m Flag
-m flag stands for "message." If you run git commit without it, Git will open a text editor so you can type a longer, multi-line message. For quick commits, the -m flag is the most common approach.SECTION 5
Writing Meaningful Commit Messages
A commit without a good message is like a labeled jar with no label — you will forget what is inside. The commit message is your future self's lifeline and your teammate's guide. Let's break down what makes a commit message meaningful versus useless.
| Quality | Bad Example ✗ | Good Example ✓ |
|---|---|---|
| Specific | "fixed stuff" | "Fix crash when user submits empty form" |
| Concise | "I changed the color of the button on the homepage from blue to green because the client asked for it in the meeting last Tuesday" | "Change homepage button color to green per client request" |
| Imperative mood | "Added new tests" | "Add unit tests for login module" |
| Purposeful | "update" | "Update README with installation instructions" |
| Single-focus | "Fix bug and add feature and refactor code" | "Fix off-by-one error in score calculation" |
Good vs. Bad Commit Messages
The Convention: Imperative Mood
The widely accepted convention is to write commit messages in the imperative mood — as if you are giving a command. Instead of "Added tests" or "Adding tests," write "Add tests." A helpful trick: your message should complete the sentence "If applied, this commit will _______." For example, "If applied, this commit will add unit tests for login module." If it reads naturally, you have the right tense.
- ✓ Keep the subject line under 50 characters — this ensures it displays fully in most Git tools.
- ✓ Capitalize the first word — treat it like a sentence title.
- ✓ Do not end with a period — the subject line is a title, not a full sentence.
- ✓ One commit = one logical change — avoid bundling unrelated changes together.
KEY TAKEAWAY
"stuff" on every box would make unpacking a nightmare. But labels like "Kitchen — pots and pans" and "Bedroom — winter blankets" tell you exactly what is inside. Commit messages work the same way: be specific, be concise, and future-you will thank you.SECTION 6
Worked Example — A Full Commit Workflow
Let's walk through a realistic scenario. You are building a Python calculator app, and you just finished adding a square-root function. Here is exactly how you would create a commit.
Committing a New Feature in a Python Project
- 1
Step 1 — Check What Changed
Rungit statusin your terminal. Git responds showing thatcalculator.pyhas been modified andtests/test_sqrt.pyis a new untracked file. This tells you exactly which files have been touched since the last commit.Two files detected: one modified, one new. - 2
Step 2 — Stage the Relevant Files
Rungit add calculator.py tests/test_sqrt.pyto move both files into the staging area. If you only wanted to commit one file, you would add just that file. This gives you fine-grained control over your snapshot.Both files are now staged and ready for commit. - 3
Step 3 — Verify the Staging Area
Rungit statusagain. Now Git shows both files under "Changes to be committed" in green. This confirmation step prevents you from accidentally including (or forgetting) a file.Staging area matches your intention — two files ready. - 4
Step 4 — Write a Meaningful Message and Commit
Rungit commit -m "Add square root function with input validation". Notice the message uses imperative mood ("Add" not "Added"), describes the specific change ("square root function"), and mentions a key detail ("with input validation"). Git responds with the new commit's hash, the branch name, and a summary of changes.Commite4a9b71created. 2 files changed, 24 insertions, 0 deletions. - 5
Step 5 — Verify the Commit in the Log
Rungit log --onelineto see a compact list of recent commits. Your new commit appears at the top with its short hash and message. This is the history that your teammates will read to understand how the project evolved.e4a9b71 Add square root function with input validation— your commit is now permanently recorded.
SECTION 7
Best Practices & Common Mistakes
Knowing how to commit is the first step, but knowing when and what to commit separates beginners from effective developers. The table below contrasts strong habits with common pitfalls.
| Best Practice ✓ | Common Mistake ✗ |
|---|---|
| Commit after each logical unit of work (one feature, one bug fix). | Wait until the end of the day and dump everything into one massive commit. |
| Write descriptive messages that explain what and why. | Use vague messages like "update" or "WIP" for permanent commits. |
Review staged files with git status before committing. | Blindly run git add . and commit without checking what is staged. |
| Keep sensitive data (passwords, API keys) out of commits. | Accidentally commit a file containing passwords — it stays in history forever. |
Use a .gitignore file to exclude generated files and dependencies. | Commit large binary files or virtual environment folders that bloat the repository. |
Best Practices vs. Common Mistakes
KEY TAKEAWAY
git log) and understand the project's journey without opening a single file.SECTION 8
Connection to Advanced Git Concepts
Once you are comfortable with basic commits, you will encounter more advanced Git features that build directly on the commit workflow. The table below gives you a preview of where this foundational skill leads.
| Basic Concept (This Lesson) | Advanced Concept (Future Learning) |
|---|---|
| Single linear chain of commits | Branching — create parallel timelines to develop features independently |
| Commits stay on your local machine | Pushing & Pulling — sync commits with a remote server like GitHub |
| One person making commits | Merge & Pull Requests — combine work from multiple developers and review code |
Viewing history with git log | Git Blame & Bisect — trace which commit introduced a specific bug |
Writing messages with -m | Conventional Commits — a structured format like feat: or fix: used in professional teams |
From Basic Commits to Advanced Git
Every one of these advanced tools depends on having a clean, well-documented commit history. If your commit messages are vague or your commits mix unrelated changes, features like git bisect (which finds the exact commit that caused a bug) become unreliable. The habits you build now — atomic commits and meaningful messages — are the foundation for professional software development.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Show answer
Question 2: BASIC CALCULATION
app.py, style.css, and index.html. You only want to commit the changes to app.py and index.html. Write the exact Git commands you would type, including a good commit message, assuming the change was fixing a broken navigation menu.Show answer
git add app.py index.html to stage only the two relevant files. Then run git commit -m "Fix broken navigation menu links". Notice that style.css is deliberately left out of the staging area because it is not related to the navigation fix. The commit message uses imperative mood ("Fix" not "Fixed"), is specific about what was broken ("navigation menu links"), and stays under 50 characters. You could later commit style.css separately with its own descriptive message.Question 3: INTERMEDIATE
git log --oneline output from their project. Identify which commit messages are poorly written and rewrite them following best practices.
f3a12bc asdfasdf
d92e1f4 Fix email validation to reject addresses without @ symbol
a81bc90 updated stuff
c44de21 Added homepage banner and fixed footer and changed database schemaShow answer
d92e1f4 is well-written — it uses imperative mood, is specific, and focuses on one change. The other three need improvement. Commit f3a12bc is meaningless gibberish; without knowing what the change was, you might rewrite it as "Add password reset form to settings page" (assuming that was the actual change). Commit a81bc90 is too vague; a better version might be "Update user profile page layout." Commit c44de21 bundles three unrelated changes into one commit. It should have been split into three separate commits, such as "Add homepage banner image," "Fix footer alignment on mobile," and "Add email column to users table." Each commit should represent one logical change.Question 4: APPLIED
calculate_average() divides by zero when the input list is empty. You add a check for an empty list and also write a new test in test_stats.py. Describe your complete commit workflow, including which files to stage together and what your commit message should say. Should this be one commit or two?Show answer
git status to confirm which files changed. Then run git add stats.py test_stats.py to stage both files. Finally, run git commit -m "Fix division by zero in calculate_average for empty lists". This message explains the specific bug (division by zero), the function affected (calculate_average), and the trigger condition (empty lists). If you had also refactored an unrelated function during the same coding session, that refactor should be a separate commit with its own message.Question 5: CRITICAL THINKING
Show answer
git bisect can automatically find the exact commit that introduced a bug, but this only works if commits are atomic and clearly labeled. A massive commit with the message "various changes" makes pinpointing the source of a bug nearly impossible. Finally, professional employers and open-source maintainers often evaluate developers partly by their commit history. Clean, well-documented commits signal professionalism and thoughtfulness.SUMMARY
Lesson Summary
Summary
A Git commit is a permanent snapshot of your project that records the state of all staged files, the author, a timestamp, and a commit message. The workflow flows through three zones: you edit files in the working directory, select files for the next snapshot using git add to move them into the staging area, and then run git commit to permanently save them to the repository. Each commit is identified by a unique SHA-1 hash and links to its parent commit, forming a chain of project history.
Writing meaningful commit messages is just as important as making the commit itself. Good messages use the imperative mood, stay under 50 characters, describe a single logical change, and explain what was changed and why. Following the practice of atomic commits — one commit per logical change — keeps your project history clean and prepares you for advanced Git features like branching, merging, and collaborative workflows.