Now that you understand version control, let's dive into the essential Git commands and workflows. Git might seem complex at first, but once you understand the basic commands, you'll be able to manage your code effectively and collaborate like a professional developer.
By the end of this lesson, you will:
To start tracking a project with Git, you need to initialize a repository:
# Navigate to your project directory
cd my-project
# Initialize a Git repository
git init
# Verify initialization
ls -la
# Output: You should see a .git directory
# Check initial status
git status
# Output: On branch main (or master)
# No commits yet
This creates a hidden .git
folder that contains all the Git tracking information.
:bulb: :bulb: Pro Tip Always run
git status
aftergit init
to verify your repository is properly initialized. In professional environments, also check that you're using the correct default branch name (main vs master).
To get a copy of an existing repository:
# Clone from GitHub (HTTPS)
git clone https://github.com/username/repository-name.git
# Clone into a specific directory
git clone https://github.com/username/repository-name.git my-folder
# Clone with SSH (recommended for regular contributors)
git clone git@github.com:username/repository-name.git
# Clone only the latest commit (shallow clone for large repos)
git clone --depth 1 https://github.com/username/repository-name.git
# Clone a specific branch
git clone -b branch-name https://github.com/username/repository-name.git
Scenario: Joining a new development team
Solution: Clone the team's repository and set up your local environment
Impact: Immediate productivity with proper version control from day one
The most important command to understand what's happening:
git status
# Short format for quick overview
git status -s
# Output explanation:
# ?? - Untracked files
# M - Modified files (staged)
# M - Modified files (not staged)
# A - Added files
# D - Deleted files
# Show ignored files too
git status --ignored
This shows:
Indicator | Meaning | Action Needed |
---|---|---|
?? | Untracked file | git add to track |
M (green) | Modified & staged | Ready to commit |
M (red) | Modified, not staged | git add to stage |
A | New file added | Ready to commit |
D | File deleted | Ready to commit |
R | File renamed | Ready to commit |
To start tracking a new file:
# Add a specific file
git add filename.txt
# Add multiple files
git add file1.txt file2.txt
# Add all files in current directory
git add .
# Add all files with a specific extension
git add *.js
The staging area is like a preparation area for your commits:
# Stage a modified file
git add modified-file.txt
# Stage all changed files
git add -A
# Stage only modified files (not new files)
git add -u
A commit is a snapshot of your repository:
# Commit with a message
git commit -m "Add new feature"
# Commit with a detailed message
git commit -m "Add user authentication" -m "- Implemented login functionality
- Added password encryption
- Created user session management"
# Add and commit in one command (only for tracked files)
git commit -am "Update existing files"
# Open editor for detailed commit message
git commit
# Sign commits for security (requires GPG setup)
git commit -S -m "Add secure feature"
:bulb: :bulb: Pro Tip Write commit messages that explain WHY, not just WHAT. Future you (and your teammates) will thank you. Example: "Add input validation to prevent SQL injection" instead of just "Add validation".
# View commit history
git log
# View compact history (one line per commit)
git log --oneline
# View last n commits
git log -n 5
# View commits with file changes
git log --stat
# View commits with actual changes
git log -p
# Pretty format with graph
git log --graph --pretty=format:'%C(red)%h%C(reset) -%C(yellow)%d%C(reset) %s %C(green)(%cr) %C(blue)<%an>%C(reset)'
# Filter by author
git log --author="John"
# Filter by date
git log --since="2 weeks ago"
git log --after="2023-01-01" --before="2023-12-31"
# Search commit messages
git log --grep="bug fix"
# Show unstaged changes
git diff
# Show staged changes
git diff --staged
# or
git diff --cached
# Show changes in a specific file
git diff filename.txt
# Show changes between commits
git diff commit1 commit2
# Remove file from repository and filesystem
git rm filename.txt
# Remove file from repository but keep in filesystem
git rm --cached filename.txt
# Remove directory
git rm -r directory-name
# Rename or move a file
git mv old-name.txt new-name.txt
# Move to different directory
git mv file.txt directory/file.txt
# Unstage a specific file
git reset HEAD filename.txt
# Unstage all files
git reset HEAD
# Discard changes in working directory
git checkout -- filename.txt
# Discard all changes
git checkout -- .
# Change the last commit message
git commit --amend -m "New commit message"
# Add forgotten files to last commit
git add forgotten-file.txt
git commit --amend --no-edit
Create a .gitignore
file to specify files Git should ignore:
# .gitignore example
# Ignore all .log files
*.log
# Ignore node_modules directory
node_modules/
# Ignore all files in build directory
build/
# Ignore specific file
secret-config.json
# Don't ignore important.log even though *.log is ignored
!important.log
# Ignore all .txt files in doc directory
doc/**/*.txt
Common patterns to ignore:
.DS_Store
, Thumbs.db
).vscode/
, .idea/
)node_modules/
, vendor/
)dist/
, build/
).env
, .env.local
)*.log
)# Set globally (for all repositories)
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
# Set locally (for current repository only)
git config user.name "Your Name"
git config user.email "your.email@example.com"
# Set default editor
git config --global core.editor "code --wait" # VS Code
git config --global core.editor "nano" # Nano
git config --global core.editor "vim" # Vim
# Enable color output
git config --global color.ui auto
# Set default branch name
git config --global init.defaultBranch main
# Configure line endings
git config --global core.autocrlf true # Windows
git config --global core.autocrlf input # Mac/Linux
# Create shortcuts
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
Good commit message:
Add user authentication system
- Implement login and logout functionality
- Add password hashing with bcrypt
- Create session management
- Add remember me feature
Fixes #123
git diff
git status
# Never commit sensitive data
# Before committing, check for:
git diff --staged | grep -E "(password|api_key|secret|token)"
# Use git-secrets to prevent accidental commits
# Installation: brew install git-secrets
git secrets --install
git secrets --register-aws
:warning: :warning: Security Alert Never commit: API keys, passwords, private keys, .env files with secrets, database credentials, or any sensitive configuration. Use environment variables and .gitignore properly.
# Add these to your ~/.gitconfig
[alias]
st = status -s
co = checkout
br = branch
ci = commit
last = log -1 HEAD --stat
unstage = reset HEAD --
visual = !gitk
lg = log --oneline --graph --decorate --all
# Save work in progress without committing
git stash save "WIP: feature description"
# List all stashes
git stash list
# Apply latest stash
git stash pop
# Apply specific stash
git stash apply stash@{2}
# Stage parts of files interactively
git add -p
# Choose what to stage:
# y - stage this hunk
# n - don't stage this hunk
# s - split into smaller hunks
# e - manually edit the hunk
# Find when a bug was introduced
git bisect start
git bisect bad # Current version is bad
git bisect good v1.0 # v1.0 was good
# Search for code in history
git log -S "function_name" --source --all
Command | Description | When to Use |
---|---|---|
git init |
Initialize new repository | Starting a new project |
git clone <url> |
Clone existing repository | Joining a project |
git status |
Check repository status | Before any operation |
git add <file> |
Stage changes | Before committing |
git commit -m "msg" |
Create commit | After staging changes |
git log --oneline |
View commit history | Review project history |
git diff |
Show unstaged changes | Before staging |
git diff --staged |
Show staged changes | Before committing |
Command | Description | When to Use |
---|---|---|
git rm <file> |
Remove file | Delete tracked files |
git rm --cached <file> |
Untrack file | Keep file, stop tracking |
git mv <old> <new> |
Move/rename file | Reorganizing files |
git checkout -- <file> |
Discard changes | Undo modifications |
git reset HEAD <file> |
Unstage file | Remove from staging |
git clean -fd |
Remove untracked files | Clean working directory |
Command | Description | When to Use |
---|---|---|
git stash |
Save work temporarily | Switch context quickly |
git stash pop |
Restore stashed work | Resume previous work |
git commit --amend |
Modify last commit | Fix recent mistakes |
git revert <commit> |
Undo specific commit | Safe history reversal |
git reset --hard HEAD~1 |
Delete last commit | Dangerous but useful |
git reflog |
Show all actions | Recover lost commits |
Solution: You're not in a Git repository. Run git init
or navigate to the correct directory.
Prevention: Always check your current directory with pwd
and verify .git
folder exists.
Solution: Use git add <file>
to stage your changes before committing.
Prevention: Run git status
to see which files need staging.
Solution:
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
Prevention: Configure Git immediately after installation.
Solution:
# Remove file from history (WARNING: This rewrites history)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/sensitive-file" \
--prune-empty --tag-name-filter cat -- --all
# Force push to remote (coordinate with team)
git push --force --all
Prevention: Use .gitignore
and pre-commit hooks to check for sensitive patterns.
Solution: We'll cover this in detail in the branching lesson, but basic approach:
<<<<<<<
, =======
, >>>>>>>
)Challenge: Create a professional Git repository for a personal project
Requirements:
Starter Code:
# Create project directory
mkdir my-awesome-project
cd my-awesome-project
# Initialize Git repository
git init
# Create README
echo "# My Awesome Project" > README.md
echo "Description of your project here" >> README.md
# Create .gitignore
echo "# OS Files" > .gitignore
echo ".DS_Store" >> .gitignore
echo "Thumbs.db" >> .gitignore
# Your turn: Continue building your repository!
# 1. Initialize repository (already done above)
# 2. Add and commit README
git add README.md
git commit -m "Initial commit: Add project README"
# 3. Add and commit .gitignore
git add .gitignore
git commit -m "Add .gitignore for OS files"
# 4. Create a source file
echo "print('Hello, Git!')" > main.py
git add main.py
git commit -m "Add main program file"
# 5. View history in different formats
git log --oneline
git log --graph --pretty=format:'%h -%d %s (%cr) <%an>'
git log --stat
# 6. Amend the last commit (add more to main.py)
echo "# This is my first Git project" >> main.py
git add main.py
git commit --amend -m "Add main program file with header comment"
You've learned the essential Git commands for:
These commands form the foundation of version control with Git. Practice them regularly, and they'll become second nature!
Now that you can work with Git locally, it's time to learn how to share your code with others using GitHub!