Git: Installation, Configuration, and Usage
Git is the world’s most widely used distributed version control system. Every change you make to a file, every experimental feature you try, every collaboration with a teammate — Git tracks it all, giving you a complete history you can inspect, compare, and roll back at any time. Whether you are working alone on a personal project or contributing to a codebase with hundreds of developers, Git is the tool that keeps everything organised.
Why Git?
| Benefit | What It Means in Practice |
|---|---|
| Version history | Every saved snapshot is recoverable — no more final_v3_REAL.txt
|
| Branching | Experiment freely without touching working code |
| Collaboration | Multiple people work on the same project simultaneously without overwriting each other |
| Distributed | Every developer has a full copy of the repository — no single point of failure |
| Speed | Almost all operations are local and happen in milliseconds |
| Accountability | Every commit records who changed what and when |
Installing Git on Linux
Debian / Ubuntu
1
2
sudo apt-get update
sudo apt-get install git-all
Red Hat / CentOS / Fedora
1
2
3
4
5
# CentOS / RHEL (older systems)
sudo yum install git-all
# Fedora / RHEL 8+ (modern systems)
sudo dnf install git-all
Verify the Installation
1
2
git --version
# git version 2.43.0
Tip: If you need a version newer than what your distribution ships, add the official Git PPA (Ubuntu:
sudo add-apt-repository ppa:git-core/ppa) or build from source via git-scm.com.
Configuring Git
Before making any commits, tell Git who you are. This identity is embedded in every commit you create and cannot be changed after the fact without rewriting history.
Set Your Identity
1
2
git config --global user.name "Jane Smith"
git config --global user.email "jane.smith@example.com"
Set Your Default Editor
Git opens a text editor for commit messages when you do not use -m. Set it to your preferred tool:
1
2
3
git config --global core.editor "vim" # Vim
git config --global core.editor "nano" # Nano
git config --global core.editor "code --wait" # VS Code
Set the Default Branch Name
Modern convention uses main instead of master for the default branch:
1
git config --global init.defaultBranch main
Useful Aliases
Aliases shorten commands you type dozens of times a day:
1
2
3
4
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.lg "log --oneline --graph --decorate --all"
Now git st runs git status, and git lg shows a visual branch graph.
Verify Your Configuration
1
2
3
git config --list # All settings
git config user.name # One specific setting
git config --list --show-origin # Settings and where each comes from
Configuration Scope
Git has three configuration levels, each overriding the one above it:
| Scope | Flag | File Location | Applies To |
|---|---|---|---|
| System | --system |
/etc/gitconfig |
Every user on the machine |
| Global | --global |
~/.gitconfig |
All repos for your user account |
| Local | --local |
.git/config |
The current repository only |
Omit --global inside a project directory to set repo-specific settings (e.g. a different email for work vs. personal projects).
Core Concepts
Before diving into commands, understanding a few key terms makes everything click.
Working Directory — the files you see and edit on disk.
Staging Area (Index) — a preparation zone where you assemble exactly what will go into the next commit. You can stage some files and leave others out.
Repository (.git) — the database Git uses to store every commit, branch, tag, and configuration value. Created by git init and lives in a hidden .git/ folder.
Commit — an immutable snapshot of the staging area at a point in time, identified by a SHA-1 hash (e.g. a3f4c21).
Branch — a lightweight, movable pointer to a commit. Creating a branch is instant and costs almost nothing.
HEAD — a special pointer that tells Git which branch (and therefore which commit) you are currently working on.
The Core Workflow
1. Initialise a Repository
1
2
mkdir my-project && cd my-project
git init
This creates a hidden .git/ directory. Your project is now a Git repository.
2. Check Status
1
git status
git status is the command you will run more than any other. It tells you which files are untracked, modified, or staged — and what branch you are on.
3. Stage Changes
1
2
3
4
5
git add README.md # Stage a specific file
git add src/ # Stage an entire directory
git add *.py # Stage all Python files
git add . # Stage everything in the current directory
git add -p # Interactive: stage individual hunks (chunks) within files
Tip:
git add -p(patch mode) is one of Git’s most powerful features. It lets you review each changed block and decide whether to stage it — perfect for committing logically separate changes that you edited in the same session.
4. Commit
1
git commit -m "Add user authentication module"
For a multi-line commit message (subject + body):
1
2
git commit
# Opens your editor — first line is subject, blank line, then body
5. View History
1
2
3
4
5
6
7
git log # Full history
git log --oneline # One line per commit
git log --oneline --graph --all # Visual branch graph
git log -5 # Last 5 commits only
git log --author="Jane" # Commits by a specific author
git log --since="2 weeks ago" # Commits in the last two weeks
git show a3f4c21 # Full details of one commit
6. See What Changed
1
2
3
git diff # Changes in working directory (not yet staged)
git diff --staged # Changes staged but not yet committed
git diff main..feature # Difference between two branches
Branching and Merging
Branches are Git’s killer feature. They let you develop features, fix bugs, and run experiments in complete isolation from your stable code.
Create and Switch Branches
1
2
3
4
5
6
7
8
git branch feature/login # Create a branch
git checkout feature/login # Switch to it
# Or do both in one command (preferred):
git checkout -b feature/login
# Git 2.23+ modern syntax:
git switch -c feature/login
List and Delete Branches
1
2
3
4
git branch # List local branches (* marks current)
git branch -a # List local and remote branches
git branch -d feature/login # Delete a merged branch (safe)
git branch -D feature/login # Force-delete an unmerged branch
Merge a Branch
1
2
git checkout main
git merge feature/login
Git performs a fast-forward merge if the branch has not diverged, or creates a merge commit if both branches have new commits. Use --no-ff to always create a merge commit (preserves branch history):
1
git merge --no-ff feature/login -m "Merge feature/login into main"
Resolving Merge Conflicts
When two branches modify the same lines, Git cannot merge automatically and marks the conflict in the file:
1
2
3
4
5
<<<<<<< HEAD
return "Welcome back, " + username
=======
return "Hello, " + username + "!"
>>>>>>> feature/login
Edit the file to keep what you want, remove the conflict markers, then:
1
2
git add conflicted-file.py
git commit -m "Resolve merge conflict in login greeting"
Tip: Use
git mergetoolto open a visual diff tool for conflict resolution, or configure VS Code as the merge tool withgit config --global merge.tool vscode.
Rebasing (Advanced)
Rebasing rewrites commit history to produce a clean, linear sequence — preferred over merge in many team workflows:
1
2
git checkout feature/login
git rebase main
Warning: Never rebase commits that have already been pushed to a shared remote branch. Rewriting public history causes serious problems for other developers.
Working with Remote Repositories
A remote is a version of your repository hosted on a server (GitHub, GitLab, Bitbucket, or a self-hosted instance).
Connect to a Remote
1
2
3
4
5
6
7
8
# Clone an existing repository (sets up 'origin' automatically)
git clone https://github.com/user/repo.git
# Add a remote to an existing local repository
git remote add origin https://github.com/user/repo.git
# View remotes
git remote -v
Push and Pull
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Push local branch to remote (first time sets upstream tracking)
git push -u origin main
# Push after upstream is set
git push
# Fetch remote changes without merging them
git fetch origin
# Fetch and merge in one step
git pull
# Pull with rebase instead of merge (cleaner history)
git pull --rebase
The Typical Remote Workflow
1
2
3
4
5
6
7
8
9
10
git checkout -b feature/payment-api # Create feature branch
# ... make changes, git add, git commit ...
git push -u origin feature/payment-api # Push to remote
# Open a Pull Request / Merge Request on GitHub/GitLab
# After review and approval, merge on the platform
git checkout main
git pull # Sync your local main
git branch -d feature/payment-api # Clean up local branch
Undoing Mistakes
Git gives you multiple tools to undo changes depending on where in the workflow the mistake happened.
Unstage a File
1
2
git restore --staged filename.py # Modern syntax (Git 2.23+)
git reset HEAD filename.py # Older equivalent
Discard Working Directory Changes
1
2
git restore filename.py # Discard changes to one file
git restore . # Discard all uncommitted changes
Warning:
git restorepermanently discards uncommitted changes. There is no undo.
Amend the Last Commit
Fix a typo in a commit message, or add a forgotten file, without creating a new commit:
1
2
git add forgotten-file.py
git commit --amend -m "Corrected commit message"
Only amend commits that have not been pushed to a remote.
Revert a Pushed Commit
Creates a new commit that undoes a previous one — safe for shared history:
1
git revert a3f4c21
Reset to a Previous Commit
1
2
3
git reset --soft HEAD~1 # Undo last commit, keep changes staged
git reset --mixed HEAD~1 # Undo last commit, keep changes unstaged (default)
git reset --hard HEAD~1 # Undo last commit, discard all changes permanently
| Reset Mode | Commit | Staged | Working Directory |
|---|---|---|---|
--soft |
Removed | Kept | Kept |
--mixed |
Removed | Cleared | Kept |
--hard |
Removed | Cleared | Cleared |
The .gitignore File
A .gitignore file tells Git which files and directories to never track — build artefacts, secrets, editor temp files, and OS metadata have no place in version history.
1
2
# Create at the root of your repository
nano .gitignore
Example .gitignore for a Python project:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Python
__pycache__/
*.py[cod]
*.egg-info/
dist/
build/
.venv/
# Environment variables (NEVER commit secrets)
.env
*.key
*.pem
# Editor files
.vscode/
.idea/
*.swp
# OS files
.DS_Store
Thumbs.db
Important: Never commit API keys, passwords, or private certificates. If you accidentally push a secret, rotate it immediately — simply deleting the file does not remove it from Git history.
Add .gitignore to your first commit:
1
2
git add .gitignore
git commit -m "Add .gitignore"
GitHub maintains a collection of ready-made .gitignore templates for dozens of languages and frameworks at github.com/github/gitignore.
Stashing Work in Progress
git stash lets you save uncommitted changes temporarily so you can switch context (e.g. fix an urgent bug on main) without committing half-finished work.
1
2
3
4
5
6
7
git stash # Stash working directory and staged changes
git stash push -m "WIP: auth flow" # Stash with a descriptive label
git stash list # View all stashes
git stash pop # Apply the most recent stash and remove it
git stash apply stash@{2} # Apply a specific stash without removing it
git stash drop stash@{0} # Delete a specific stash
git stash clear # Delete all stashes
Tagging Releases
Tags mark specific commits as significant milestones — typically software releases.
1
2
3
4
5
6
git tag v1.0.0 # Lightweight tag
git tag -a v1.0.0 -m "Initial release" # Annotated tag (recommended)
git tag # List all tags
git push origin v1.0.0 # Push a specific tag
git push origin --tags # Push all tags
git checkout v1.0.0 # Check out a tagged commit
Quick Reference
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# Setup
git config --global user.name "Name"
git config --global user.email "email@example.com"
git config --list
# Repository
git init
git clone <url>
git status
git diff / git diff --staged
# Staging & Committing
git add <file> / git add .
git add -p # Interactive staging
git commit -m "message"
git commit --amend
# History
git log --oneline --graph --all
git show <hash>
# Branching
git checkout -b <branch>
git switch -c <branch>
git branch / git branch -d <branch>
git merge <branch>
git rebase main
# Remotes
git remote add origin <url>
git push -u origin main
git fetch / git pull
git pull --rebase
# Undoing
git restore <file> # Discard working directory changes
git restore --staged <file> # Unstage
git revert <hash> # Safe undo (creates new commit)
git reset --soft|mixed|hard HEAD~1
# Stash
git stash / git stash pop
git stash list
# Tags
git tag -a v1.0.0 -m "Release"
git push origin --tags
# Help
git help <command>
git <command> --help
Hands-On Practice Exercise
Work through these steps to cement everything you have learned:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 1. Create a new project
mkdir git-practice && cd git-practice
git init
# 2. Configure if not done globally
git config user.name "Your Name"
git config user.email "you@example.com"
# 3. Create and commit a README
echo "# Git Practice Project" > README.md
git add README.md
git commit -m "Initial commit: Add README"
# 4. Create a feature branch and add a file
git checkout -b feature/add-script
echo '#!/bin/bash' > hello.sh
echo 'echo "Hello from Git!"' >> hello.sh
chmod +x hello.sh
git add hello.sh
git commit -m "Add hello.sh greeting script"
# 5. Merge back to main
git checkout main
git merge --no-ff feature/add-script -m "Merge feature/add-script"
# 6. Review the history
git log --oneline --graph --all
# 7. Challenge: make a second commit, then undo it safely with git revert
Challenge: Intentionally create a merge conflict by editing the same line in README.md on both main and a new branch, then practice resolving it.
Best Practices
Write meaningful commit messages. A good message completes the sentence “If applied, this commit will…” — for example, “Add rate limiting to the login endpoint” rather than “fix stuff”. Use present tense and keep the subject under 50 characters.
Commit small and often. Atomic commits (one logical change per commit) are easier to review, bisect, and revert than enormous multi-hour dumps.
Never commit secrets. API keys, passwords, and certificates belong in environment variables or a secrets manager — never in a repository, even a private one.
Use branches for every change. Even for a one-line fix. The cost of a branch is near zero; the cost of breaking main is not.
Pull before you push. Always git pull --rebase before pushing to reduce conflicts and keep history linear.
Review before committing. Run git diff --staged before every commit to verify you are committing exactly what you intend.
Use a .gitignore from day one. Add it in your first commit, before any build artefacts accumulate.
Conclusion
Git’s power comes from its composability: a handful of well-understood commands — init, add, commit, branch, merge, push, pull — combine to handle workflows from a solo side project to a thousand-developer monorepo. The fundamentals covered here will carry you through the vast majority of day-to-day work. As you grow more comfortable, explore interactive rebasing (git rebase -i), git bisect for tracking down regressions, and git worktree for working on multiple branches simultaneously without stashing.
Additional Resources
- Official Git Documentation
- Pro Git Book — free, comprehensive, authoritative
- Learn Git Branching — interactive visual tutorial
- GitHub Git Cheat Sheet
- Conventional Commits — a commit message standard used by many open-source projects
- Oh My Git! — an open-source game for learning Git