02 - Local Workflow
#02 - Local Workflow
##The Daily Git Loop
Every day as a developer, you repeat this loop hundreds of times:
1
2
3
4
1. Edit a file
2. git add stage the changes you want to save
3. git commit save a permanent snapshot
4. Repeat
This module teaches you to do this loop confidently, see what you changed before you commit, and understand your project’s history.
##Setup: Create a Practice Project
1
2
3
4
5
mkdir git_practice
cd git_practice
git init
touch app.py
git status
Expected:
1
2
Untracked files:
app.py
##Your First Commit
Stage the file and commit:
1
2
git add app.py
git status
Expected:
1
2
Changes to be committed:
new file: app.py
1
git commit -m "Initial commit: create app.py"
Expected:
1
2
3
[main (root-commit) a1b2c3d] Initial commit: create app.py
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 app.py
Git shows you: the branch name, a short commit hash (a1b2c3d), the message, and a summary of what changed.
##Writing Good Commit Messages
A commit message is a note to your future self (and your teammates). Bad messages make history useless.
1
2
3
4
5
6
7
8
9
10
11
#BAD — tells you nothing
git commit -m "fix"
git commit -m "changes"
git commit -m "stuff"
git commit -m "wip"
#GOOD — tells you exactly what changed and why
git commit -m "Fix login button not responding on mobile"
git commit -m "Add email validation to signup form"
git commit -m "Remove unused imports from utils.py"
git commit -m "Update README with installation instructions"
Rule of thumb: If someone reads only your commit message with no other context, they should understand what you did.
##Making and Viewing Changes
Add some content to app.py:
1
2
echo "print('Hello, world!')" > app.py
git status
Expected:
1
2
Changes not staged for commit:
modified: app.py
Git sees the file changed but it is not staged yet. Before staging, inspect what changed:
1
git diff app.py
Expected:
1
2
3
4
5
6
diff --git a/app.py b/app.py
index e69de29..b3c5fa7 100644
--- a/app.py
+++ b/app.py
@@ -0,0 +1 @@
+print('Hello, world!')
Lines starting with + are additions. Lines starting with - are deletions. This is how you verify your change is exactly what you intended before committing.
Stage and commit:
1
2
git add app.py
git commit -m "Add hello world print statement"
##git diff vs git diff –staged
These two commands look the same but show different things. Understanding the difference is critical.
Let’s set up a scenario where you have BOTH staged and unstaged changes at once:
1
2
3
4
5
6
#Add a second line and stage it
echo "name = 'Priya'" >> app.py
git add app.py
#Now add a third line WITHOUT staging it
echo "print(name)" >> app.py
Your file now has:
- Line 2 (
name = 'Priya') — staged, will go into the next commit - Line 3 (
print(name)) — unstaged, NOT in the next commit
Now run both commands:
1
git diff app.py
Expected — shows ONLY the unstaged change (line 3):
1
+print(name)
1
git diff --staged app.py
Expected — shows ONLY the staged change (line 2):
1
+name = 'Priya'
| Command | What it compares | Shows |
|---|---|---|
git diff |
Working directory vs staging area | Unstaged changes (what’s NOT yet staged) |
git diff --staged |
Staging area vs last commit | Staged changes (what WILL go into the next commit) |
Pro habit: Always run
git diff --stagedbefore committing. It shows you exactly what snapshot you are about to save — no surprises.
Now stage and commit both changes:
1
2
git add app.py
git commit -m "Add name variable and print it"
##Viewing Commit History with git log
After several commits, see the full history:
1
git log
Expected:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
commit 9f3c1a2b4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9 (HEAD -> main)
Author: Priya Sharma <[email protected]>
Date: Mon Jul 15 10:30:00 2026 +0530
Add name variable and print it
commit 7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6
Author: Priya Sharma <[email protected]>
Date: Mon Jul 15 10:25:00 2026 +0530
Add hello world print statement
commit a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
Author: Priya Sharma <[email protected]>
Date: Mon Jul 15 10:20:00 2026 +0530
Initial commit: create app.py
For a more compact view:
1
git log --oneline
Expected:
1
2
3
9f3c1a2 Add name variable and print it
7a8b9c0 Add hello world print statement
a1b2c3d Initial commit: create app.py
For a visual graph (very useful with branches):
1
git log --oneline --graph --decorate
##Staging Multiple Files Selectively
One of Git’s most powerful features: you can make 10 changes but commit them in 3 separate, logical groups.
Suppose you edited 3 files:
1
2
3
4
5
6
touch index.html style.css README.md
echo "<h1>Hello</h1>" > index.html
echo "body { color: red; }" > style.css
echo "#My Project" > README.md
git status
Expected:
1
2
3
4
Untracked files:
README.md
index.html
style.css
Commit the HTML and CSS together (they’re related), then the README separately:
1
2
3
4
5
6
7
8
9
#First commit: the web files
git add index.html style.css
git commit -m "Add HTML structure and basic styles"
#Second commit: the documentation
git add README.md
git commit -m "Add project README"
git log --oneline
Expected:
1
2
3
4
b4f8a2c Add project README
3d9c1e0 Add HTML structure and basic styles
9f3c1a2 Add name variable and print it
...
This makes your history clean and easy to understand. Each commit tells a clear story.
##Ignoring Files with .gitignore
Some files should never be committed: compiled output, log files, API keys, IDE settings, etc.
Create some files you don’t want tracked:
1
2
3
4
touch debug.log
mkdir __pycache__
touch __pycache__/app.cpython-39.pyc
git status
Expected: Git shows these as untracked — and you don’t want to see them every time you run git status.
Create a .gitignore file:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
cat > .gitignore << 'EOF'
#Log files
*.log
#Python cache
__pycache__/
*.pyc
#macOS junk
.DS_Store
#Environment variables (NEVER commit these)
.env
EOF
Stage and commit .gitignore:
1
2
3
4
git add .gitignore
git commit -m "Add .gitignore for logs and Python cache"
git status
Expected: debug.log and __pycache__/ are no longer shown. Git is ignoring them.
Critical rule: Add
.gitignoreto every project before your first commit. Once a file is committed,.gitignorecannot untrack it without extra steps.
Common patterns:
1
2
3
4
5
6
*.log #Any file ending in .log
build/ #The entire build folder
.env #Environment variables file
node_modules/ #JavaScript dependencies (huge folder, never commit)
*.pyc #Python compiled files
.DS_Store #macOS desktop service file
##A Complete Realistic Example
Let’s simulate what a real 30-minute work session looks like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#Start of day: check where you are
git status
git log --oneline
#Make your changes (edit files in your editor)
echo "def greet(name):" >> app.py
echo " return f'Hello, {name}!'" >> app.py
#Check what changed before staging
git diff app.py
#Stage it
git add app.py
#Double-check what's about to be committed
git diff --staged app.py
#Commit with a clear message
git commit -m "Add greet() function with name parameter"
#Verify history
git log --oneline
This 7-step flow is your everyday rhythm.
##Summary
| Command | What it does |
|---|---|
git add <file> |
Stage a specific file |
git add . |
Stage all changed files at once |
git commit -m "message" |
Save staged changes permanently |
git diff |
See unstaged changes (working dir vs staging) |
git diff --staged |
See staged changes (staging vs last commit) |
git log |
See full commit history |
git log --oneline |
Compact one-line history |
git log --oneline --graph --decorate |
Visual history with branch info |
Next: 03-vi-quick-guide.md — Learn the terminal editor you will use every day