Git & GitHub track

Lesson 02 · Lessons

Everyday Work

add, commit, log, diff, .gitignore, aliases and HEAD

Lessons6 min readFree lesson

To use Git on a daily basis, you need to familiarize yourself with four commands: add, commit, log, and diff. Here, you can manage files to exclude from tracking with .gitignore, Shorten the repeat command to alias, once you understand what HEAD refers to. You can work comfortably without having to leave the terminal all day.

Learning Objectives

  • Various options of git add (-p, -u, .) can be used according to the situation.
  • You can utilize the format options of git log (--oneline, --graph, --since).
  • You can compare the differences between working directory, staging, and commit with git diff.
  • You can create .gitignore files and exclude files that are already being tracked.
  • Frequently used commands can be registered and used as git alias.
  • Can understand and utilize HEAD, HEAD~1, and HEAD^ notations.

Key concepts

1) git add option

git add .           #Change everything below the current directory
git add -u          #Only edit/delete files being tracked (excluding new files)
git add -p          #Select and stage change chunks one by one
git add src/        #Only specific directories

2) git commit option

git commit -m "message"         #Commit immediately with a one-line message
git commit                     #Open the editor and write a message
git commit --amend             #Modify last commit message (only before push)
git commit -am "message"        #add -u + commit at once (without new files)

3) git log options

git log --oneline              #one line summary
git log --oneline --graph      #branch graph
git log --since="2 weeks ago"  #period filter
git log -n 5                   #Last 5 only
git log --author="Hong Gil-dong"      #Author filter
git log -- src/main.py         #Specific file history

4) git diff

git diff                       #Working Directory vs Staging
git diff --staged              #Staging vs Latest Commit
git diff HEAD~1 HEAD           #Compare between two commits
git diff main feature          #Compare two branches

5) .gitignore

# Build output
*.o
*.class
build/

# Preferences
.env
.env.local

# OS metafile
.DS_Store
Thumbs.db

# IDE
.idea/
.vscode/

To later ignore files that are already being tracked:

git rm --cached file name
echo "file name" >> .gitignore
git commit -m "chore: ignore file name"

6) git alias

git config --global alias.st status
git config --global alias.co checkout
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.aa "add --all"

Afterwards, it is used as a shortcut like git lg.

7) Understanding HEAD

HEAD → main → (latest commit hash)
notation Meaning
HEAD Currently checked out commit
HEAD~1 One step back
HEAD~2 Two steps back
HEAD^ First Parent (same as ~1)

See as example

Example 1 — ex01_add_commit.sh: Partial staging with add -p

#!/usr/bin/env bash
REPO=$(mktemp -d); cd "$REPO"
git init -q
git config user.name "For practice" && git config user.email "[email protected]"

echo -e "line1\nline2\nline3" > file.txt
git add file.txt && git commit -q -m "init"

#Edit multiple areas simultaneously
echo "line4" >> file.txt          #Change working directory
git add file.txt                   #staging

echo "line5" >> file.txt          #Additional changes after staging

echo "=== diff (working vs staging) ==="
git diff

echo ""
echo "=== diff --staged (Staging vs HEAD) ==="
git diff --staged

rm -rf "$REPO"

Execution result

=== diff (working vs staging) ===
+line5

=== diff --staged (Staging vs HEAD) ===
+line4

Key point: git diff and git diff --staged have different comparison targets.


Example 2 — ex02_log_diff.sh: Comparing various log options

#!/usr/bin/env bash
REPO=$(mktemp -d); cd "$REPO"
git init -q
git config user.name "For practice" && git config user.email "[email protected]"

for i in 1 2 3; do
    echo "v$i" > version.txt
    git add version.txt
    git commit -q -m "chore: version $i"
done

echo "=== --oneline ==="
git log --oneline

echo ""
echo "=== --oneline --stat ==="
git log --oneline --stat

echo ""
echo "=== -n 2 ==="
git log --oneline -n 2

rm -rf "$REPO"

Execution result

=== --oneline ===
c3d4e5f chore: version 3
b2c3d4e chore: version 2
a1b2c3d chore: version 1

=== --oneline --stat ===
c3d4e5f chore: version 3
 version.txt | 2 +-
...

Key point: git log allows you to selectively view the desired level of information by combining options.


Example 3 — ex03_gitignore.sh: Create .gitignore and purge cache

#!/usr/bin/env bash
REPO=$(mktemp -d); cd "$REPO"
git init -q
git config user.name "For practice" && git config user.email "[email protected]"

echo "secret" > .env
echo "code" > main.py
git add . && git commit -q -m "init: add files"

#Now when you want to ignore .env
echo ".env" > .gitignore
git rm --cached .env
git add .gitignore
git commit -m "chore: ignore .env"

echo "=== Trace file list ==="
git ls-files

echo ""
echo "=== status ==="
git status

rm -rf "$REPO"

Execution result

=== Trace file list ===
.gitignore
main.py

=== status ===
On branch main
nothing to commit, working tree clean

Bottom line: git rm --cached doesn't delete files from disk, it just excludes them from tracking.


Example 4 — ex04_alias.sh: Registering and using alias

#!/usr/bin/env bash
REPO=$(mktemp -d); cd "$REPO"
git init -q
git config user.name "For practice" && git config user.email "[email protected]"

#Register alias only in local repository (prevent global settings contamination)
git config alias.lg "log --oneline --graph --all"
git config alias.st "status --short"

echo "first file" > a.txt
git add a.txt && git commit -q -m "first"

echo "=== git st (alias) ==="
git st

echo ""
echo "=== git lg (alias) ==="
git lg

rm -rf "$REPO"

Execution result

=== git st (alias) ===
   (nothing)

=== git lg (alias) ===
* a1b2c3d first

Bottom line: git config alias.<name> allows you to create shortcuts for complex commands.


Seeing from a different perspective

Git commands Everyday metaphor
git add -p Add each product to your shopping cart
git commit Payment completed
git log View Receipt List
git diff Compare prices before and after ordering
.gitignore Do not shop list

Common Mistakes

  1. Add unnecessary files with git add . — Set .gitignore first or use git add -p.
  2. -m "" without commit message — If you commit with an empty message, it is difficult to understand the history.
  3. Correction of commits pushed to --amend — A forced push is required, which distorts the team member’s history.
  4. Accidentally commit file .env — Sensitive information exposed to public repository; Immediately git rm --cached.
  5. HEAD~1 and HEAD^1 confused — In the merge commit, ^2 points to the second parent.

Cleanup

  • Keep commits small by selecting change chunks with git add -p.
  • git diff is a comparison of working and staging, and git diff --staged is a comparison of staging and committing.
  • Add a pattern to .gitignore, and remove already tracked files as git rm --cached.
  • Increase productivity by shortening frequently used commands with alias.
  • Refer to the N-level previous commit as HEAD~N.

Try it yourself

cd 02_Daily_Work/src
chmod +x *.sh
./ex01_add_commit.sh
./ex02_log_diff.sh
./ex03_gitignore.sh
./ex04_alias.sh

Application:

  1. Filter my recent commits by git log --since="1 week ago" --author="$(git config user.name)".
  2. Create an alias that reverts the last commit with git config --global alias.undo "reset HEAD~1 --mixed".

Example files

The runnable files used in this lesson. Copy them into your own project and experiment.

src/ex01_add_commit.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

printf 'line1\nline2\nline3\n' > file.txt
git add file.txt && git commit -q -m "init"

echo "line4" >> file.txt
git add file.txt

echo "line5" >> file.txt

echo "=== diff: Working vs Staging ==="
git diff

echo ""
echo "=== diff --staged: staging vs HEAD ==="
git diff --staged

git commit -q -m "add line4 (staged only)"
echo ""
echo "=== Changes remaining after commit ==="
git diff

rm -rf "$REPO"
src/ex02_log_diff.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

for i in 1 2 3; do
    echo "v$i" > version.txt
    git add version.txt
    git commit -q -m "chore: version $i"
done

echo "=== git log --oneline ==="
git log --oneline

echo ""
echo "=== git log --oneline -n 2 ==="
git log --oneline -n 2

echo ""
echo "=== git log --oneline --stat ==="
git log --oneline --stat

echo ""
echo "=== git diff HEAD~2 HEAD (two commits ago vs now) ==="
git diff HEAD~2 HEAD

rm -rf "$REPO"
src/ex03_gitignore.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

echo "secret_password" > .env
echo "print('hello')" > main.py
git add .
git commit -q -m "init: add files (including .env by mistake)"

echo "=== List of accidentally committed files ==="
git ls-files

#Now exclude .env from tracking
echo ".env" > .gitignore
git rm --cached .env
git add .gitignore
git commit -m "chore: stop tracking .env"

echo ""
echo "=== List of trace files after modification ==="
git ls-files

echo ""
echo "=== The .env file remains on disk ==="
ls -la .env

rm -rf "$REPO"
src/ex04_alias.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

#Register local repository alias
git config alias.lg "log --oneline --graph --all --decorate"
git config alias.st "status --short --branch"
git config alias.aa "add --all"
git config alias.cm "commit -m"

for i in 1 2; do
    echo "file$i" > "file$i.txt"
    git aa
    git cm "chore: add file$i"
done

echo "=== git st (status --short --branch) ==="
git st

echo ""
echo "=== git lg (log --oneline --graph --all) ==="
git lg

echo ""
echo "=== List of registered aliases ==="
git config --list | grep "^alias\."

rm -rf "$REPO"

Assignment

Problem 1

Write a script that reproduces the scenario below.

  1. Initialize temporary storage.
  2. Write three lines (“To Do 1”, “To Do 2”, and “To Do 3”) in notes.txt and commit.
  3. Add “To Do 4” and run git add notes.txt.
  4. Add “To Do 5” (without staging).
  5. Print git diff and git diff --staged respectively and check that the two results are different.
  • File name: hw01.sh
#Expected output (the key part)
=== diff (working vs staging) ===
+To Do 5

=== diff --staged (Staging vs HEAD) ===
+To Do 4

Problem 2

Write a script that satisfies all of the following conditions:

  1. Initialize temporary storage and create 5 commits.
  2. Add the *.log pattern to .gitignore and commit.
  3. When the debug.log file is created, check that it does not appear in git status.
  4. Print the entire commit list with git log --oneline.
  5. Print only the most recent three with git log --oneline -n 3.
  • File name: hw02.sh

Check the correct answer

After writing it yourself, compare it with the reference solution below.

Show the reference solution

Try the assignment yourself first — comparing your attempt with a working solution is where most of the learning happens.

hw01.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

printf 'To Do 1\nTo Do 2\nTo Do 3\n' > notes.txt
git add notes.txt && git commit -q -m "init: add notes"

echo "to do 4" >> notes.txt
git add notes.txt

echo "5 things to do" >> notes.txt

echo "=== diff: Working vs Staging ==="
git diff

echo ""
echo "=== diff --staged: staging vs HEAD ==="
git diff --staged

rm -rf "$REPO"
hw02.shShell
#!/usr/bin/env bash
set -euo pipefail

REPO=$(mktemp -d)
cd "$REPO"
git init -q -b main
git config user.name "For practice" && git config user.email "[email protected]"
    git config commit.gpgsign false

for i in 1 2 3 4 5; do
    echo "commit $i" > "file$i.txt"
    git add "file$i.txt"
    git commit -q -m "chore: add file$i"
done

echo "*.log" > .gitignore
git add .gitignore
git commit -q -m "chore: ignore *.log files"

echo "some debug info" > debug.log

echo "=== git status (.log file should not be visible) ==="
git status

echo ""
echo "=== git log --oneline (full) ==="
git log --oneline

echo ""
echo "=== git log --oneline -n 3 (last 3) ==="
git log --oneline -n 3

rm -rf "$REPO"

Learn this lesson with a mentor

Work through the Git & GitHub track on your own, or join a guided cohort at our Pitampura campus and online.

Call NowEnroll Now