<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: bolontiku</title>
    <description>The latest articles on Forem by bolontiku (@bolontiku_eb2e9933657c822).</description>
    <link>https://forem.com/bolontiku_eb2e9933657c822</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3646674%2Fe5aeaea0-9812-4bda-8f2f-eb0435995ef5.png</url>
      <title>Forem: bolontiku</title>
      <link>https://forem.com/bolontiku_eb2e9933657c822</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/bolontiku_eb2e9933657c822"/>
    <language>en</language>
    <item>
      <title>SELECT Basics — Asking Questions</title>
      <dc:creator>bolontiku</dc:creator>
      <pubDate>Thu, 04 Dec 2025 15:49:40 +0000</pubDate>
      <link>https://forem.com/bolontiku_eb2e9933657c822/select-basics-asking-questions-1lle</link>
      <guid>https://forem.com/bolontiku_eb2e9933657c822/select-basics-asking-questions-1lle</guid>
      <description>&lt;p&gt;&lt;small&gt;This is Lesson 1 of a free 8-lesson SQL course on &lt;a href="https://nemorize.com/preview/019ae982-2948-731a-94bf-3cb2e45a3f31" rel="noopener noreferrer"&gt;Nemorize&lt;/a&gt;. Continue learning with spaced repetition quizzes.&lt;/small&gt;&lt;/p&gt;

&lt;h2 id="introduction-talking-to-your-database"&gt;Introduction: Talking to Your Database 🗣️&lt;/h2&gt;

&lt;p&gt;Imagine walking into a massive library with millions of books. You need specific information, but you can't read every book. Instead, you ask a librarian: "Show me all mystery novels published after 2020, sorted by author." That librarian is &lt;strong&gt;SQL&lt;/strong&gt; (Structured Query Language), and the library is your &lt;strong&gt;database&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;SQL is the universal language for asking databases questions. Whether you're using PostgreSQL, MySQL, SQLite, or SQL Server, the core SQL commands work the same way. Today, you'll learn to ask your first questions using &lt;strong&gt;SELECT&lt;/strong&gt; statements.&lt;/p&gt;

&lt;h2 id="core-concepts-building-your-first-queries"&gt;Core Concepts: Building Your First Queries 🏗️&lt;/h2&gt;

&lt;h3 id="the-select-statement-your-basic-question"&gt;The SELECT Statement: Your Basic Question&lt;/h3&gt;

&lt;p&gt;Every SQL query starts with a question: "What data do I want to see?" The &lt;strong&gt;SELECT&lt;/strong&gt; statement is how you ask that question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Structure:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT column_name
FROM table_name;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Think of a database &lt;strong&gt;table&lt;/strong&gt; like a spreadsheet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rows&lt;/strong&gt; = individual records (like customers, products, orders)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Columns&lt;/strong&gt; = attributes or properties (like name, price, date)&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;+----+------------+-------+--------+
| id | name       | price | stock  |
+----+------------+-------+--------+
| 1  | Laptop     | 999   | 15     |
| 2  | Mouse      | 25    | 150    |
| 3  | Keyboard   | 75    | 80     |
| 4  | Monitor    | 350   | 45     |
+----+------------+-------+--------+
Table: products
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Selecting Specific Columns:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price FROM products;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This returns only the name and price columns. Use commas to separate multiple columns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Selecting All Columns:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT * FROM products;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The asterisk (*) means "all columns." It's quick for exploration, but in production code, specify exact columns for clarity and performance.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; SQL keywords (SELECT, FROM, WHERE) are case-insensitive, but it's convention to write them in UPPERCASE for readability.&lt;/p&gt;

&lt;h3 id="the-where-clause-filtering-your-results"&gt;The WHERE Clause: Filtering Your Results 🔍&lt;/h3&gt;

&lt;p&gt;Most of the time, you don't want ALL records—you want specific ones. The &lt;strong&gt;WHERE&lt;/strong&gt; clause filters results based on conditions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Structure:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT column_name
FROM table_name
WHERE condition;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Comparison Operators:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------+----------------------+
| Operator | Meaning              |
+----------+----------------------+
| =        | Equal to             |
| !=       | Not equal to         |
| &amp;lt;        | Less than            |
| &amp;gt;        | Greater than         |
| &amp;lt;=       | Less than or equal   |
| &amp;gt;=       | Greater than or equal|
+----------+----------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price 
FROM products 
WHERE price &amp;gt; 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This returns only products with prices greater than 100.&lt;/p&gt;

&lt;h3 id="combining-conditions-and-or-not"&gt;Combining Conditions: AND, OR, NOT 🔗&lt;/h3&gt;

&lt;p&gt;Real questions often need multiple conditions. Use logical operators to combine them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AND&lt;/strong&gt; - Both conditions must be true:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price 
FROM products 
WHERE price &amp;gt; 50 AND stock &amp;lt; 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;OR&lt;/strong&gt; - At least one condition must be true:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price 
FROM products 
WHERE price &amp;lt; 30 OR stock &amp;gt; 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;NOT&lt;/strong&gt; - Negates a condition:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name 
FROM products 
WHERE NOT price &amp;gt; 100;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(This finds products with price ≤ 100)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Combining Multiple Operators:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price 
FROM products 
WHERE (price &amp;gt; 50 AND stock &amp;gt; 20) OR name = 'Mouse';
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Use parentheses to control evaluation order, just like in math. Without them, AND is evaluated before OR.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logical Flow Diagram:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;        WHERE condition
              |
         ┌────┴────┐
       TRUE      FALSE
         |
    Include row  Skip row
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="pattern-matching-with-like"&gt;Pattern Matching with LIKE 🎯&lt;/h3&gt;

&lt;p&gt;Sometimes you don't know the exact value—you're looking for a pattern. The &lt;strong&gt;LIKE&lt;/strong&gt; operator searches for text patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wildcards:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;%&lt;/strong&gt; = any number of characters (including zero)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;_&lt;/strong&gt; = exactly one character&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;+----------+------------------------+
| Pattern  | Matches                |
+----------+------------------------+
| 'A%'     | Starts with A          |
| '%a'     | Ends with a            |
| '%app%'  | Contains 'app'         |
| '_at'    | 3 letters ending in 'at'|
| 'L____'  | 5 letters starting with L|
+----------+------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name FROM products WHERE name LIKE 'M%';
-- Finds: Mouse, Monitor

SELECT name FROM products WHERE name LIKE '%top';
-- Finds: Laptop

SELECT name FROM products WHERE name LIKE '%o%';
-- Finds: Laptop, Mouse, Monitor
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Case Sensitivity:&lt;/strong&gt; LIKE behavior varies by database. PostgreSQL is case-sensitive; use &lt;strong&gt;ILIKE&lt;/strong&gt; for case-insensitive searches. MySQL is case-insensitive by default.&lt;/p&gt;

&lt;h3 id="handling-null-values"&gt;Handling NULL Values 🕳️&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NULL&lt;/strong&gt; represents missing or unknown data. It's not zero, not empty string—it's the absence of a value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; You CANNOT use = or != with NULL. Use special operators:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name FROM products WHERE description IS NULL;
-- Finds products with no description

SELECT name FROM products WHERE description IS NOT NULL;
-- Finds products with a description
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Why NULL is Special:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+-------------------+---------+
| Expression        | Result  |
+-------------------+---------+
| NULL = NULL       | NULL    |
| NULL != NULL      | NULL    |
| NULL &amp;gt; 5          | NULL    |
| 5 + NULL          | NULL    |
| NULL IS NULL      | TRUE    |
+-------------------+---------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;NULL "infects" operations—any calculation involving NULL returns NULL.&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;Mnemonic:&lt;/strong&gt; Think of NULL as "No Understanding of Literal Logic"—it doesn't behave like normal values.&lt;/p&gt;

&lt;h3 id="sorting-results-order-by"&gt;Sorting Results: ORDER BY 📊&lt;/h3&gt;

&lt;p&gt;Results come in no guaranteed order unless you specify. The &lt;strong&gt;ORDER BY&lt;/strong&gt; clause sorts results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Basic Structure:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT column_name
FROM table_name
ORDER BY column_name ASC|DESC;
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ASC&lt;/strong&gt; = ascending (default, smallest to largest, A to Z)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DESC&lt;/strong&gt; = descending (largest to smallest, Z to A)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price FROM products ORDER BY price ASC;
-- Cheapest first

SELECT name, price FROM products ORDER BY price DESC;
-- Most expensive first

SELECT name, price FROM products ORDER BY name;
-- Alphabetical (ASC is default)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Multiple Sort Columns:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price, stock 
FROM products 
ORDER BY price DESC, stock ASC;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This sorts by price (descending) first. When prices are equal, it sorts by stock (ascending).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sort Order Visualization:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Unsorted:  [3, 1, 4, 1, 5]
   |
ORDER BY value ASC
   |
   v
Sorted:    [1, 1, 3, 4, 5]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="limiting-results-limit"&gt;Limiting Results: LIMIT 🎚️&lt;/h3&gt;

&lt;p&gt;Sometimes you only want the first few results—say, the top 10 products or a sample for testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LIMIT&lt;/strong&gt; restricts the number of rows returned:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price 
FROM products 
ORDER BY price DESC 
LIMIT 5;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This returns the 5 most expensive products.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Database Differences:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostgreSQL, MySQL, SQLite: &lt;strong&gt;LIMIT&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;SQL Server: &lt;strong&gt;TOP&lt;/strong&gt; (e.g., &lt;code&gt;SELECT TOP 5 name FROM products&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Oracle: &lt;strong&gt;ROWNUM&lt;/strong&gt; or &lt;strong&gt;FETCH FIRST&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For universal compatibility, learn your specific database's syntax, but LIMIT is most common.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Tip:&lt;/strong&gt; Always use ORDER BY with LIMIT. Without it, you get arbitrary rows—not useful!&lt;/p&gt;

&lt;h2 id="detailed-examples"&gt;Detailed Examples 📖&lt;/h2&gt;

&lt;h3 id="example-1-finding-affordable-products-in-stock"&gt;Example 1: Finding Affordable Products in Stock&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; An online store wants to show customers products under $100 that are currently in stock.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price, stock
FROM products
WHERE price &amp;lt; 100 AND stock &amp;gt; 0
ORDER BY price ASC;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SELECT name, price, stock&lt;/strong&gt; - We want these three columns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FROM products&lt;/strong&gt; - Looking in the products table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WHERE price &amp;lt; 100 AND stock &amp;gt; 0&lt;/strong&gt; - Two conditions: affordable AND available&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORDER BY price ASC&lt;/strong&gt; - Show cheapest first&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------+-------+-------+
| name     | price | stock |
+----------+-------+-------+
| Mouse    | 25    | 150   |
| Keyboard | 75    | 80    |
+----------+-------+-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Why it works:&lt;/strong&gt; The AND operator ensures BOTH conditions are met. Sorting by price helps customers find the best deals first.&lt;/p&gt;

&lt;h3 id="example-2-searching-for-products-by-name"&gt;Example 2: Searching for Products by Name&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; A customer types "key" in the search box. Find all matching products.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price
FROM products
WHERE name LIKE '%key%'
ORDER BY name;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LIKE '%key%'&lt;/strong&gt; - The % wildcards mean "key" can appear anywhere in the name&lt;/li&gt;
&lt;li&gt;Case-insensitive in most databases, so matches "Keyboard", "Monkey Wrench", "Turkey Baster"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORDER BY name&lt;/strong&gt; - Alphabetical results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------+-------+
| name     | price |
+----------+-------+
| Keyboard | 75    |
+----------+-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Real-world usage:&lt;/strong&gt; Search functionality in e-commerce sites uses LIKE extensively. For better performance at scale, use full-text search features.&lt;/p&gt;

&lt;h3 id="example-3-top-3-most-expensive-products"&gt;Example 3: Top 3 Most Expensive Products&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Display featured premium products on the homepage.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT name, price
FROM products
WHERE stock &amp;gt; 0
ORDER BY price DESC
LIMIT 3;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;WHERE stock &amp;gt; 0&lt;/strong&gt; - Only show available products (don't advertise out-of-stock items)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORDER BY price DESC&lt;/strong&gt; - Most expensive first&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LIMIT 3&lt;/strong&gt; - Only top 3&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------+-------+
| name     | price |
+----------+-------+
| Laptop   | 999   |
| Monitor  | 350   |
| Keyboard | 75    |
+----------+-------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Why the order matters:&lt;/strong&gt; Without ORDER BY, LIMIT would give you 3 random products. Always pair them.&lt;/p&gt;

&lt;h3 id="example-4-finding-products-with-missing-descriptions"&gt;Example 4: Finding Products with Missing Descriptions&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Scenario:&lt;/strong&gt; Quality control needs to find products without descriptions to update them.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SELECT id, name, price
FROM products
WHERE description IS NULL
ORDER BY id;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Breakdown:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;description IS NULL&lt;/strong&gt; - Finds records where description was never set&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NOT&lt;/strong&gt; using = NULL (common mistake!)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORDER BY id&lt;/strong&gt; - Systematic order for team to work through&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Common mistake avoided:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;-- WRONG:
WHERE description = NULL  -- Returns nothing!

-- RIGHT:
WHERE description IS NULL  -- Works correctly
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Business value:&lt;/strong&gt; Data quality checks like this keep your database clean and complete.&lt;/p&gt;

&lt;h2 id="common-mistakes"&gt;Common Mistakes ⚠️&lt;/h2&gt;

&lt;h3 id="using-with-null"&gt;1. Using = with NULL&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;-- WRONG:
SELECT * FROM products WHERE description = NULL;
-- Returns zero rows even if NULL values exist

-- RIGHT:
SELECT * FROM products WHERE description IS NULL;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="forgetting-quotes-around-text"&gt;2. Forgetting Quotes Around Text&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;-- WRONG:
SELECT * FROM products WHERE name = Mouse;
-- Database thinks Mouse is a column name!

-- RIGHT:
SELECT * FROM products WHERE name = 'Mouse';
-- Single quotes for text values
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="confusing-andor-logic"&gt;3. Confusing AND/OR Logic&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;-- This probably doesn't do what you think:
SELECT * FROM products 
WHERE price &amp;gt; 100 OR price &amp;lt; 50 AND stock &amp;gt; 20;
-- AND is evaluated first!

-- Clearer with parentheses:
SELECT * FROM products 
WHERE (price &amp;gt; 100 OR price &amp;lt; 50) AND stock &amp;gt; 20;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="using-limit-without-order-by"&gt;4. Using LIMIT Without ORDER BY&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;-- WRONG (unpredictable):
SELECT * FROM products LIMIT 5;
-- Which 5? Random!

-- RIGHT (intentional):
SELECT * FROM products ORDER BY price DESC LIMIT 5;
-- Top 5 by price
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="case-sensitivity-with-like"&gt;5. Case Sensitivity with LIKE&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;-- PostgreSQL:
SELECT * FROM products WHERE name LIKE 'laptop';
-- Doesn't match 'Laptop' (case-sensitive)

-- Use ILIKE for case-insensitive:
SELECT * FROM products WHERE name ILIKE 'laptop';
-- Matches 'Laptop', 'LAPTOP', 'laptop'
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="wildcard-position-matters"&gt;6. Wildcard Position Matters&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;LIKE 'M%'   -- Starts with M (fast)
LIKE '%M'   -- Ends with M (slower)
LIKE '%M%'  -- Contains M (slowest)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Leading wildcards prevent index usage, making queries slow on large tables.&lt;/p&gt;

&lt;h2 id="key-takeaways"&gt;Key Takeaways 🎯&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SELECT&lt;/strong&gt; specifies which columns to retrieve; &lt;strong&gt;FROM&lt;/strong&gt; specifies which table&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WHERE&lt;/strong&gt; filters rows based on conditions (comparison operators: =, !=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AND&lt;/strong&gt; requires all conditions true; &lt;strong&gt;OR&lt;/strong&gt; requires at least one true&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LIKE&lt;/strong&gt; matches patterns using % (any characters) and _ (one character)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NULL&lt;/strong&gt; requires &lt;strong&gt;IS NULL&lt;/strong&gt; or &lt;strong&gt;IS NOT NULL&lt;/strong&gt; (never use = or !=)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ORDER BY&lt;/strong&gt; sorts results (ASC ascending, DESC descending)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LIMIT&lt;/strong&gt; restricts the number of rows returned&lt;/li&gt;
&lt;li&gt;Always use quotes around text values: &lt;code&gt;'text'&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;SQL keywords are case-insensitive, but write them UPPERCASE by convention&lt;/li&gt;
&lt;li&gt;Pair ORDER BY with LIMIT for predictable results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🤔 &lt;strong&gt;Did you know?&lt;/strong&gt; SQL was invented in the 1970s at IBM. The original name was SEQUEL (Structured English Query Language), but it was shortened to SQL due to trademark issues. Some people still pronounce it "sequel" while others say "S-Q-L"—both are correct!&lt;/p&gt;

&lt;h2 id="further-study"&gt;📚 Further Study&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Nemorize&lt;/strong&gt; - &lt;a href="https://nemorize.com/preview/019ae982-2948-731a-94bf-3cb2e45a3f31" rel="noopener noreferrer"&gt;https://nemorize.com/preview/019ae982-2948-731a-94bf-3cb2e45a3f31&lt;/a&gt; - SQL Fundamentals — Query Any Database&lt;/li&gt;

&lt;li&gt;
&lt;strong&gt;W3Schools SQL Tutorial&lt;/strong&gt; - &lt;a href="https://www.w3schools.com/sql/" rel="noopener noreferrer"&gt;https://www.w3schools.com/sql/&lt;/a&gt; - Interactive SQL exercises with instant feedback&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL Official Documentation - SELECT&lt;/strong&gt; - &lt;a href="https://www.postgresql.org/docs/current/sql-select.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/sql-select.html&lt;/a&gt; - Comprehensive reference for SELECT syntax&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLBolt - Interactive Lessons&lt;/strong&gt; - &lt;a href="https://sqlbolt.com/" rel="noopener noreferrer"&gt;https://sqlbolt.com/&lt;/a&gt; - Learn SQL through hands-on practice with immediate results&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="quick-reference-card"&gt;📋 Quick Reference Card&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;╔════════════════════════════════════════════════════╗
║            SQL SELECT BASICS CHEAT SHEET           ║
╠════════════════════════════════════════════════════╣
║ SELECT col1, col2 FROM table;                      ║
║   → Get specific columns                           ║
║                                                    ║
║ SELECT * FROM table;                               ║
║   → Get all columns                                ║
║                                                    ║
║ WHERE price &amp;gt; 100                                  ║
║   → Filter: =, !=, &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;=                    ║
║                                                    ║
║ WHERE price &amp;gt; 50 AND stock &amp;gt; 10                    ║
║   → Both conditions must be true                   ║
║                                                    ║
║ WHERE price &amp;lt; 30 OR stock &amp;gt; 100                    ║
║   → At least one condition true                    ║
║                                                    ║
║ WHERE name LIKE 'M%'                               ║
║   → Starts with M (% = any chars, _ = one char)    ║
║                                                    ║
║ WHERE description IS NULL                          ║
║   → Find NULL values (not = NULL!)                 ║
║                                                    ║
║ ORDER BY price DESC                                ║
║   → Sort (ASC ascending, DESC descending)          ║
║                                                    ║
║ LIMIT 10                                           ║
║   → Return only first 10 rows                      ║
║                                                    ║
║ Full Example:                                      ║
║ SELECT name, price FROM products                   ║
║ WHERE price &amp;lt; 100 AND stock &amp;gt; 0                    ║
║ ORDER BY price ASC                                 ║
║ LIMIT 5;                                           ║
╚════════════════════════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;🔧 &lt;strong&gt;Try this:&lt;/strong&gt; Open a SQL environment (try &lt;a href="https://sqliteonline.com/" rel="noopener noreferrer"&gt;https://sqliteonline.com/&lt;/a&gt; for instant practice) and create a simple table with a few rows. Then practice each type of query from this lesson. The best way to learn SQL is to write it!&lt;/p&gt;

</description>
      <category>sql</category>
    </item>
    <item>
      <title>The Git Mental - Model Snapshots not Diffs</title>
      <dc:creator>bolontiku</dc:creator>
      <pubDate>Thu, 04 Dec 2025 15:42:41 +0000</pubDate>
      <link>https://forem.com/bolontiku_eb2e9933657c822/the-git-mental-model-snapshots-not-diffs-3450</link>
      <guid>https://forem.com/bolontiku_eb2e9933657c822/the-git-mental-model-snapshots-not-diffs-3450</guid>
      <description>&lt;p&gt;&lt;small&gt;This is Lesson 1 of a free 8-lesson Git course on &lt;a href="https://nemorize.com/preview/019ae981-1807-79b3-b117-358d2262f429" rel="noopener noreferrer"&gt;Nemorize&lt;/a&gt;. Continue learning with spaced repetition quizzes.&lt;/small&gt;&lt;/p&gt;

&lt;h2 id="introduction-why-git-feels-confusing-and-how-to-fix-it"&gt;Introduction: Why Git Feels Confusing (And How to Fix It) 💡&lt;/h2&gt;

&lt;p&gt;If you've ever felt lost using Git, copy-pasting commands from Stack Overflow without understanding what they do, you're not alone. The problem isn't you — it's that most Git tutorials teach you &lt;strong&gt;commands&lt;/strong&gt; before teaching you &lt;strong&gt;concepts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Imagine learning to drive by memorizing "turn the wheel 37 degrees left, press pedal 2 inches" without understanding that the wheel controls direction and the pedal controls speed. That's how most people learn Git!&lt;/p&gt;

&lt;p&gt;This lesson builds the &lt;strong&gt;mental model&lt;/strong&gt; that makes Git intuitive. Once you understand how Git thinks, the commands will make perfect sense. 🧠&lt;/p&gt;

&lt;h2 id="what-git-actually-is-a-content-addressable-filesystem"&gt;What Git Actually Is: A Content-Addressable Filesystem 📦&lt;/h2&gt;

&lt;p&gt;Let's start with the big reveal: &lt;strong&gt;Git is not primarily a version control system&lt;/strong&gt;. At its core, Git is a &lt;strong&gt;content-addressable filesystem&lt;/strong&gt; with a version control interface built on top.&lt;/p&gt;

&lt;p&gt;What does "content-addressable" mean? It means Git stores data (files, directories, commits) and gives each piece a unique address based on its &lt;strong&gt;content&lt;/strong&gt;. This address is a &lt;strong&gt;SHA-1 hash&lt;/strong&gt; — a 40-character string like &lt;code&gt;a3f5c9b2e8d1f6a7b4c3e2d1f0a9b8c7d6e5f4a3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;🤔 &lt;strong&gt;Did you know?&lt;/strong&gt; The same file content always produces the same hash, no matter where or when you save it. This makes Git incredibly efficient — if two branches have the same file, Git only stores it once!&lt;/p&gt;

&lt;h3 id="the-key-insight-snapshots-not-diffs"&gt;The Key Insight: Snapshots, Not Diffs 📸&lt;/h3&gt;

&lt;p&gt;Here's the fundamental concept that changes everything:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git does not store changes (diffs). Git stores complete snapshots of your project.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most other version control systems store the original file and then a series of changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Version 1: "Hello world"
Version 2: Change line 1 to "Hello Git"
Version 3: Add line 2 "Welcome"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git doesn't work this way. Instead, it takes a &lt;strong&gt;complete snapshot&lt;/strong&gt; of your entire project at each commit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Commit 1: [Complete snapshot of all files]
Commit 2: [Complete snapshot of all files]
Commit 3: [Complete snapshot of all files]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;💡 &lt;strong&gt;Efficiency tip:&lt;/strong&gt; Don't worry about storage! If a file hasn't changed between commits, Git doesn't store it again — it just creates a link to the previous version. Git is incredibly space-efficient.&lt;/p&gt;

&lt;p&gt;This snapshot model is why Git is so powerful for branching and merging. Each commit is a complete, self-contained snapshot, not dependent on a chain of changes.&lt;/p&gt;

&lt;h2 id="the-three-areas-where-your-code-lives"&gt;The Three Areas: Where Your Code Lives 🏠&lt;/h2&gt;

&lt;p&gt;Git organizes your work into &lt;strong&gt;three distinct areas&lt;/strong&gt;. Understanding these is crucial:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+------------------+       +------------------+       +------------------+
|   WORKING        |       |    STAGING       |       |   REPOSITORY     |
|   DIRECTORY      | ----&amp;gt; |    AREA          | ----&amp;gt; |   (.git folder)  |
|                  | git   |   (INDEX)        | git   |                  |
| Your actual      | add   | Prepared         | commit| Permanent        |
| files you edit   |       | snapshot         |       | history          |
+------------------+       +------------------+       +------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="working-directory-working-tree"&gt;1. Working Directory (Working Tree) 🌳&lt;/h3&gt;

&lt;p&gt;This is your &lt;strong&gt;playground&lt;/strong&gt; — the actual files and folders you see and edit. When you open a file in your text editor, you're working in the working directory.&lt;/p&gt;

&lt;p&gt;Think of it as your &lt;strong&gt;drafting table&lt;/strong&gt; where you make changes freely. Nothing here affects Git's history until you explicitly tell Git about it.&lt;/p&gt;

&lt;h3 id="staging-area-index"&gt;2. Staging Area (Index) 🎬&lt;/h3&gt;

&lt;p&gt;The staging area is Git's &lt;strong&gt;unique feature&lt;/strong&gt; that confuses many beginners but becomes incredibly powerful once you understand it.&lt;/p&gt;

&lt;p&gt;Think of the staging area as a &lt;strong&gt;photography studio&lt;/strong&gt; where you arrange exactly what you want in your snapshot before taking the picture. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add specific files: "I want this file in my next snapshot"&lt;/li&gt;
&lt;li&gt;Add parts of files: "I want these 3 lines but not those 5 lines"&lt;/li&gt;
&lt;li&gt;Review what you've staged before committing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The command &lt;code&gt;git add&lt;/code&gt; moves changes from the working directory to the staging area.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Why have a staging area?&lt;/strong&gt; It lets you create &lt;strong&gt;clean, logical commits&lt;/strong&gt;. You might have changed 10 files while working, but you can stage and commit related changes separately, making your history clear and meaningful.&lt;/p&gt;

&lt;h3 id="repository.git-folder"&gt;3. Repository (.git folder) 🏛️&lt;/h3&gt;

&lt;p&gt;The repository is Git's &lt;strong&gt;permanent database&lt;/strong&gt; — the &lt;code&gt;.git&lt;/code&gt; folder in your project. This is where Git stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All your commits (complete snapshots)&lt;/li&gt;
&lt;li&gt;All your branches&lt;/li&gt;
&lt;li&gt;All your history&lt;/li&gt;
&lt;li&gt;All the metadata&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you run &lt;code&gt;git commit&lt;/code&gt;, Git takes everything from the staging area and creates a &lt;strong&gt;permanent snapshot&lt;/strong&gt; in the repository.&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Important:&lt;/strong&gt; Once something is committed to the repository, it's nearly impossible to lose. Even if you "delete" a commit, Git usually keeps it for weeks. This is why Git is so safe!&lt;/p&gt;

&lt;h2 id="how-commits-actually-work"&gt;How Commits Actually Work 🔗&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;commit&lt;/strong&gt; is Git's fundamental unit. Let's demystify what a commit really is.&lt;/p&gt;

&lt;p&gt;A commit contains:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A complete snapshot&lt;/strong&gt; of all staged files&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt;: author name, email, timestamp, commit message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parent commit(s)&lt;/strong&gt;: pointer(s) to the previous commit(s)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A unique SHA-1 hash&lt;/strong&gt;: the commit's address&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;code&gt;+-----------------------------------+
| Commit: a3f5c9b                   |
|-----------------------------------|
| Author: Jane Developer            |
| Date: 2024-01-15 10:30            |
| Message: "Add login feature"      |
|-----------------------------------|
| Parent: f2e4d8a                   |
|-----------------------------------|
| Snapshot:                         |
|   - index.html    [hash: d3a2...]|
|   - style.css     [hash: b7f1...]|
|   - app.js        [hash: e8c4...]|
+-----------------------------------+
           |
           v
+-----------------------------------+
| Commit: f2e4d8a (parent)          |
|-----------------------------------|
| Author: John Coder                |
| Date: 2024-01-14 15:20            |
| Message: "Initial commit"         |
+-----------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each commit &lt;strong&gt;points to its parent&lt;/strong&gt;, creating a &lt;strong&gt;chain&lt;/strong&gt; (actually a directed acyclic graph, but we'll get to that later). This chain is your project's history.&lt;/p&gt;

&lt;p&gt;🧠 &lt;strong&gt;Mnemonic:&lt;/strong&gt; Think of commits as &lt;strong&gt;linked snapshots&lt;/strong&gt; — each one is complete but knows where it came from.&lt;/p&gt;

&lt;h2 id="detailed-examples-the-three-areas-in-action"&gt;Detailed Examples: The Three Areas in Action 🎯&lt;/h2&gt;

&lt;h3 id="example-1-creating-your-first-commit"&gt;Example 1: Creating Your First Commit&lt;/h3&gt;

&lt;p&gt;Let's walk through creating a commit step by step, tracking what happens in each area:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starting state:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Working Directory:    (empty new project)
Staging Area:         (empty)
Repository:           (empty)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Create a file&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;echo "Hello Git" &amp;gt; readme.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;Working Directory:    readme.txt (modified/new)
Staging Area:         (empty)
Repository:           (empty)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git doesn't know about this file yet. It's only in your working directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Stage the file&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git add readme.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;Working Directory:    readme.txt
Staging Area:         readme.txt (staged for commit)
Repository:           (empty)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git has prepared a snapshot that includes this file. The staging area now holds a copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Commit the snapshot&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git commit -m "Add readme file"
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;Working Directory:    readme.txt
Staging Area:         (clean - matches repository)
Repository:           Commit a3f5c9b: "Add readme file"
                         ↳ Contains: readme.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git has created a permanent snapshot in the repository! The staging area is now clean because it matches what's in the repository.&lt;/p&gt;

&lt;h3 id="example-2-multiple-changes-selective-staging"&gt;Example 2: Multiple Changes, Selective Staging&lt;/h3&gt;

&lt;p&gt;This example shows why the staging area is powerful:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Starting state:&lt;/strong&gt; You have a committed project with &lt;code&gt;index.html&lt;/code&gt; and &lt;code&gt;styles.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You make changes:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Fix a bug in index.html
# Add a new feature in index.html
# Update colors in styles.css
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;Working Directory:    index.html (modified)
                      styles.css (modified)
Staging Area:         (clean)
Repository:           Last commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;You want two separate commits&lt;/strong&gt; (one for the bugfix, one for the feature + styling). You can stage selectively:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Stage only the bugfix lines from index.html
git add -p index.html
# (select only the bugfix hunks)

git commit -m "Fix navigation bug"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now commit 1 contains only the bugfix. Then:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Stage the rest
git add index.html styles.css
git commit -m "Add color theme feature"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now commit 2 contains the feature and styling changes. Your history is clean and logical! 🎉&lt;/p&gt;

&lt;h3 id="example-3-understanding-file-states"&gt;Example 3: Understanding File States&lt;/h3&gt;

&lt;p&gt;A file in your project can be in one of several &lt;strong&gt;states&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;+----------------+     +----------------+     +----------------+
|   UNTRACKED    |     |   UNMODIFIED   |     |   MODIFIED     |
| (new file,     |----&amp;gt;| (committed,    |----&amp;gt;| (changed since |
|  git doesn't   | git | hasn't been    | edit| last commit)   |
|  know about it)| add | changed)       |     |                |
+----------------+     +----------------+     +----------------+
                              |                      |
                              v                      v
                       +----------------+     +----------------+
                       |   REMOVED      |     |    STAGED      |
                       | (deleted,      |     | (ready to be   |
                       |  staged for    |     |  committed)    |
                       |  deletion)     |     |                |
                       +----------------+     +----------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can check file states with &lt;code&gt;git status&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git status
On branch main

Changes to be committed:  # STAGED
  (use "git restore --staged &amp;lt;file&amp;gt;..." to unstage)
        modified:   index.html

Changes not staged for commit:  # MODIFIED
  (use "git add &amp;lt;file&amp;gt;..." to stage)
        modified:   styles.css

Untracked files:  # UNTRACKED
  (use "git add &amp;lt;file&amp;gt;..." to include)
        new-feature.js
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="example-4-the-commit-graph"&gt;Example 4: The Commit Graph&lt;/h3&gt;

&lt;p&gt;Commits form a &lt;strong&gt;graph structure&lt;/strong&gt;. Here's a simple linear history:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A &amp;lt;-- B &amp;lt;-- C &amp;lt;-- D (main)
                  ^
                  HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each letter is a commit. Arrows point to parent commits. &lt;code&gt;main&lt;/code&gt; is a &lt;strong&gt;branch&lt;/strong&gt; (just a pointer to a commit). &lt;code&gt;HEAD&lt;/code&gt; points to where you are now.&lt;/p&gt;

&lt;p&gt;When you create a new commit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git commit -m "Add new feature"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git creates commit E:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;A &amp;lt;-- B &amp;lt;-- C &amp;lt;-- D &amp;lt;-- E (main)
                        ^
                        HEAD
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;main&lt;/code&gt; branch moves forward automatically, and &lt;code&gt;HEAD&lt;/code&gt; follows it.&lt;/p&gt;

&lt;p&gt;💡 &lt;strong&gt;Key insight:&lt;/strong&gt; Branches are just &lt;strong&gt;moveable pointers&lt;/strong&gt; to commits. Creating a branch doesn't copy any files — it just creates a new pointer!&lt;/p&gt;

&lt;h2 id="why-this-mental-model-makes-everything-easy"&gt;Why This Mental Model Makes Everything Easy 🚀&lt;/h2&gt;

&lt;p&gt;Once you understand that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Git stores snapshots&lt;/strong&gt;, not changes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three areas exist&lt;/strong&gt; (working, staging, repository)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commits are linked snapshots&lt;/strong&gt; with metadata&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Branches are just pointers&lt;/strong&gt; to commits&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;...then all Git commands become logical:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git add&lt;/code&gt; = "Move this to staging"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git commit&lt;/code&gt; = "Create a snapshot from staging"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git checkout&lt;/code&gt; = "Move HEAD to a different commit"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git branch&lt;/code&gt; = "Create a new pointer"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git merge&lt;/code&gt; = "Combine two commit histories"&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase&lt;/code&gt; = "Replay commits on a different base"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No more memorizing! Each command is just manipulating these fundamental structures.&lt;/p&gt;

&lt;h2 id="common-mistakes"&gt;Common Mistakes ⚠️&lt;/h2&gt;

&lt;h3 id="mistake-1-thinking-git-stores-diffs"&gt;Mistake 1: Thinking Git Stores Diffs&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Wrong thinking:&lt;/strong&gt; "Git saves the changes I made to each file."&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Correct thinking:&lt;/strong&gt; "Git saves complete snapshots. It can show me diffs by comparing snapshots."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; This misconception makes branching and merging seem scary. If you think Git stores diffs, you imagine complex chains of changes that might conflict. But since Git stores complete snapshots, branches are just different snapshot sequences!&lt;/p&gt;

&lt;h3 id="mistake-2-confusing-working-directory-and-repository"&gt;Mistake 2: Confusing Working Directory and Repository&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Wrong:&lt;/strong&gt; "If I delete a file, it's gone from Git forever."&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Correct:&lt;/strong&gt; "If I delete a file from my working directory, it's still in the repository until I commit that deletion."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rm important.txt  # Deleted from working directory only!
git status        # Shows "deleted: important.txt"
git restore important.txt  # Brings it back from repository!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The file is safe in the repository until you &lt;code&gt;git add&lt;/code&gt; the deletion and commit it.&lt;/p&gt;

&lt;h3 id="mistake-3-not-using-the-staging-area"&gt;Mistake 3: Not Using the Staging Area&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Wrong pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git add .
git commit -m "Made changes"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This stages &lt;strong&gt;everything&lt;/strong&gt; indiscriminately, leading to messy commits that mix unrelated changes.&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Better pattern:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git add file1.js file2.js  # Only related changes
git commit -m "Add user authentication"
git add file3.css
git commit -m "Update button styles"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each commit has a clear, single purpose.&lt;/p&gt;

&lt;h3 id="mistake-4-fearing-commits"&gt;Mistake 4: Fearing Commits&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Wrong:&lt;/strong&gt; "I'll wait until everything is perfect before committing."&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Correct:&lt;/strong&gt; "I'll commit small, logical units of work frequently."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Frequent commits give you more &lt;strong&gt;save points&lt;/strong&gt; to return to. If you break something, you can easily go back. Commits are cheap — Git is designed for many small commits, not few giant ones.&lt;/p&gt;

&lt;h3 id="mistake-5-not-understanding-head"&gt;Mistake 5: Not Understanding HEAD&lt;/h3&gt;

&lt;p&gt;❌ &lt;strong&gt;Wrong:&lt;/strong&gt; "HEAD is magical and confusing."&lt;/p&gt;

&lt;p&gt;✅ &lt;strong&gt;Correct:&lt;/strong&gt; "HEAD is just a pointer showing where I am right now (usually pointing to a branch, which points to a commit)."&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HEAD --&amp;gt; main --&amp;gt; commit D
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you checkout a different branch, HEAD moves:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HEAD --&amp;gt; feature --&amp;gt; commit F
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That's it! No magic.&lt;/p&gt;

&lt;h2 id="key-takeaways"&gt;Key Takeaways 🎓&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git is a content-addressable filesystem&lt;/strong&gt; that stores data by content hash&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git stores snapshots&lt;/strong&gt;, not diffs — each commit is a complete picture of your project&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Three areas exist:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Working Directory&lt;/strong&gt;: Your actual files (the drafting table)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Staging Area&lt;/strong&gt;: What you're preparing to commit (the photography studio)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repository&lt;/strong&gt;: Permanent history (the archive)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Commits are linked snapshots&lt;/strong&gt; containing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Complete file snapshot&lt;/li&gt;
&lt;li&gt;Metadata (author, date, message)&lt;/li&gt;
&lt;li&gt;Parent commit pointer(s)&lt;/li&gt;
&lt;li&gt;Unique SHA-1 hash&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The staging area lets you craft clean, logical commits&lt;/strong&gt; by selecting exactly what to snapshot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Branches are just moveable pointers&lt;/strong&gt; to commits — cheap and easy to create&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HEAD is a pointer&lt;/strong&gt; showing where you are (usually points to a branch)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;This mental model makes all Git commands logical&lt;/strong&gt; — they're just manipulating these structures&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;🔧 &lt;strong&gt;Try this:&lt;/strong&gt; After this lesson, run &lt;code&gt;git status&lt;/code&gt; in one of your projects. You'll now understand exactly what each section means: which area each file is in, and what Git is telling you about the state of your project!&lt;/p&gt;

&lt;h2 id="further-study"&gt;📚 Further Study&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nemorize&lt;/strong&gt; &lt;a href="https://nemorize.com/preview/019ae981-1807-79b3-b117-358d2262f429" rel="noopener noreferrer"&gt;https://nemorize.com/preview/019ae981-1807-79b3-b117-358d2262f429&lt;/a&gt; - Git Mastery — Version Control Without Fear&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git Internals - Plumbing and Porcelain&lt;/strong&gt; (Official Git Book): &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain" rel="noopener noreferrer"&gt;https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain&lt;/a&gt;
Deep dive into how Git stores objects and creates snapshots&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A Visual Git Reference&lt;/strong&gt;: &lt;a href="https://marklodato.github.io/visual-git-guide/index-en.html" rel="noopener noreferrer"&gt;https://marklodato.github.io/visual-git-guide/index-en.html&lt;/a&gt;
Excellent diagrams showing how Git commands affect the three areas&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Git from the Bottom Up&lt;/strong&gt;: &lt;a href="https://jwiegley.github.io/git-from-the-bottom-up/" rel="noopener noreferrer"&gt;https://jwiegley.github.io/git-from-the-bottom-up/&lt;/a&gt;
Builds Git understanding from the object database up&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id="quick-reference-card"&gt;📋 Quick Reference Card&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;+------------------------------------------------------------------+
|                   GIT MENTAL MODEL CHEAT SHEET                   |
+------------------------------------------------------------------+
| CORE CONCEPT                                                      |
|   Git stores SNAPSHOTS, not changes                              |
|   Each commit = complete picture of your project                 |
+------------------------------------------------------------------+
| THREE AREAS                                                       |
|   Working Directory → Staging Area → Repository                  |
|   (your files)        (prepared)      (permanent)                |
+------------------------------------------------------------------+
| KEY COMMANDS                                                      |
|   git add &amp;lt;file&amp;gt;       Move working → staging                    |
|   git commit -m "..."  Move staging → repository (create snapshot)|
|   git status           See state of all three areas              |
|   git log              View commit history                       |
+------------------------------------------------------------------+
| WHAT IS A COMMIT?                                                 |
|   ✓ Complete snapshot of all files                               |
|   ✓ Author, date, message                                        |
|   ✓ Parent commit pointer(s)                                     |
|   ✓ Unique SHA-1 hash (address)                                  |
+------------------------------------------------------------------+
| FILE STATES                                                       |
|   Untracked  → git doesn't know about it                         |
|   Unmodified → committed, hasn't changed                         |
|   Modified   → changed since last commit                         |
|   Staged     → ready to be committed                             |
+------------------------------------------------------------------+
| REMEMBER                                                          |
|   • Commits are CHEAP → commit often!                            |
|   • Staging area = craft logical commits                         |
|   • Branches = just pointers to commits                          |
|   • HEAD = where you are now                                     |
+------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You now have the foundational mental model that makes Git make sense! In the next lessons, we'll build on this foundation to master branching, merging, rebasing, and fixing mistakes — all of which will be easy now that you understand how Git really works. 🚀&lt;/p&gt;

</description>
      <category>git</category>
    </item>
  </channel>
</rss>
