Programming

Git and GitHub: The Complete Practical Guide for Developers (2026)

2026-07-05·13 min read
#Git#GitHub#version control#developer tools

Git is the most used tool in software development. Not the most popular programming language, not the hottest framework — Git. Every developer, every team, every company uses it. Yet most developers only know a handful of commands.

This guide covers everything you actually need: from the basics to advanced workflows that real teams use in production.

Git Fundamentals: What's Actually Happening

Before memorizing commands, understand what Git does:

Git is a content-addressable filesystem. Every commit is a snapshot of your entire project at a point in time, identified by a SHA-1 hash. Branches are just pointers to commits. Tags are named pointers to specific commits.

This mental model makes everything else click. When you git merge, Git is figuring out how to combine two snapshots. When you git rebase, Git is replaying commits on top of another commit.

The Three States

  • Working directory: Files on your disk, as you see them
  • Staging area (index): Files you've marked as ready to commit
  • Repository: The committed history (.git directory)

Every Git operation moves files between these three states.

The 20 Commands You Actually Need

Daily Commands (Use These Every Day)

# Check what's changed
git status

# Stage specific files
git add file1.js file2.js

# Stage everything
git add .

# Commit with a message
git commit -m "Add user authentication"

# Push to remote
git push origin main

# Pull latest changes
git pull origin main

Branching Commands

# Create and switch to a new branch
git checkout -b feature/user-profile

# Switch back to main
git checkout main

# List all branches
git branch -a

# Delete a local branch (after merge)
git branch -d feature/user-profile

# Delete a remote branch
git push origin --delete feature/user-profile

History and Inspection

# View commit history (one line per commit)
git log --oneline

# View history with a graph
git log --oneline --graph --all

# See what changed in the last commit
git show HEAD

# See who changed each line of a file
git blame filename.js

Fixing Mistakes

# Undo changes in working directory (before staging)
git checkout -- file.js

# Unstage a file (after git add, before commit)
git restore --staged file.js

# Undo the last commit but keep changes
git reset --soft HEAD~1

# Undo the last commit and discard changes (dangerous!)
git reset --hard HEAD~1

# Create a new commit that undoes a previous commit
git revert abc1234

Stashing (Save Work Without Committing)

# Save current changes temporarily
git stash

# Stash with a message
git stash save "WIP: user profile UI"

# List stashes
git stash list

# Apply the most recent stash
git stash pop

# Apply a specific stash
git stash pop stash@{2}

# Delete all stashes
git stash clear

Branching Strategies That Actually Work

Git Flow (For Established Products)

main    ────●────●────●────●────●──────── (production releases)
              \         /
develop ──●────●───●──●────●────●────●─── (integration branch)
              \      /
feature  ───●───●───● (feature work)
  • main: Production-ready code only
  • develop: Integration branch for features
  • feature/*: Individual features, merged to develop
  • release/*: Release preparation
  • hotfix/*: Emergency production fixes

When to use: Established products with scheduled releases. Overkill for small teams.

GitHub Flow (For Most Teams)

main    ──●────●────●────●────●────●──
            \       /
feature   ──●──●───● (PR → review → merge)
  • main: Always deployable
  • feature branches: Short-lived, merged via pull request
  • One rule: Never commit directly to main

When to use: Most teams, most projects. Simple and effective.

Trunk-Based Development (For High-Velocity Teams)

main    ──●─●─●─●─●─●─●─●─●─●─●─●─●──
           \  /\ /\ /
feature   ──●●●●●● (very short-lived branches, hours not days)
  • Everyone commits to main (or very short-lived branches)
  • Feature flags control what's visible
  • Continuous deployment

When to use: High-velocity teams with strong CI/CD and test coverage.

Merge vs Rebase: The Eternal Question

Merge (Safe, Messy History)

git checkout main
git merge feature/profile

Creates a merge commit. History is preserved but can look messy:

*   Merge branch 'feature/profile'
|\
| * Add profile page
| * Add avatar upload
| * Add profile API
* | Update homepage
|/
* Initial commit

Rebase (Clean History, Rewrites History)

git checkout feature/profile
git rebase main
git checkout main
git merge feature/profile  # Fast-forward merge

History is linear:

* Add profile page
* Add avatar upload
* Add profile API
* Update homepage
* Initial commit

When to Use Each

  • Merge: When working with shared branches (main, develop). Safe, doesn't rewrite history.
  • Rebase: On your own feature branches before merging. Gives clean history.

Golden rule: Never rebase commits that have been pushed and might be used by others.

Pull Requests: How to Do Them Right

Writing a Good PR Description

## What
Brief description of what this PR does.

## Why
Why this change is needed (link to issue/ticket).

## How
Key implementation decisions.

## Testing
- [ ] Unit tests pass
- [ ] Manual testing done
- [ ] No console errors

## Screenshots
(If UI changes)

PR Best Practices

  1. Keep PRs small. Under 400 lines of changes. Reviewers can't effectively review 2000-line PRs.
  2. One PR, one concern. Don't mix a bug fix with a refactor and a new feature.
  3. Self-review before requesting review. Read your own diff. You'll catch obvious issues.
  4. Respond to feedback gracefully. Don't take it personally.
  5. Use draft PRs for work-in-progress that you want early feedback on.

.gitignore Essentials

Every project needs a good .gitignore. Here's a comprehensive one:

# Dependencies
node_modules/
vendor/
__pycache__/
*.pyc

# Build output
dist/
build/
out/
.next/
target/

# Environment variables
.env
.env.local
.env.production

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

# Logs
*.log
npm-debug.log*

# Test coverage
coverage/
.nyc_output/

# Misc
.cache/
tmp/
*.local

Pro tip: Visit gitignore.io to generate a .gitignore for your specific stack.

Git Aliases: Speed Up Your Workflow

Add these to your ~/.gitconfig:

[alias]
    co = checkout
    br = branch
    ci = commit
    st = status
    unstage = reset HEAD --
    last = log -1 HEAD
    visual = log --oneline --graph --all --decorate
    amend = commit --amend --no-edit
    lg = log --oneline --graph --all --decorate --abbrev-commit

Now git lg gives you a beautiful history graph, git co main switches branches, and git ci -m "msg" commits.

Common Git Scenarios (Solved)

"I committed to the wrong branch"

# Undo the commit (keep changes) and switch branches
git reset --soft HEAD~1
git stash
git checkout correct-branch
git stash pop
git add .
git commit -m "Your message"

"I need to change my last commit message"

git commit --amend -m "New message"
# If already pushed:
git push --force-with-lease

"I accidentally committed a large file"

# Remove from the last commit
git rm --cached large-file.zip
git commit --amend

# If it's in older commits, use git filter-branch or BFG
# BFG Repo-Cleaner is faster and easier
bfg --delete-files large-file.zip
git reflog expire --expire=now --all
git gc --prune=now --aggressive

"I need to undo a merge"

# Find the commit before the merge
git log --oneline

# Reset to before the merge
git reset --hard <commit-before-merge>

# If already pushed
git push --force-with-lease

"I want to see a specific file's history"

# Full history of a file
git log --follow -- path/to/file.js

# See what changed in each commit
git log -p --follow -- path/to/file.js

# Use gitk for visual history
gitk --follow -- path/to/file.js

"Conflict resolution"

# When merge conflicts occur
git status  # See conflicted files

# Open the files and look for:
# <<<<<<< HEAD
# your changes
# =======
# their changes
# >>>>>>>

# After resolving:
git add resolved-file.js
git commit -m "Resolve merge conflict in resolved-file.js"

# If you want to abandon the merge entirely:
git merge --abort

GitHub-Specific Features Worth Using

GitHub Actions (CI/CD)

Automate testing and deployment:

# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
      - run: npm ci
      - run: npm test
      - run: npm run build

GitHub Projects

Kanban boards integrated with issues and PRs. Free for public and private repos.

Dependabot

Automated dependency updates. Add .github/dependabot.yml:

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

GitHub Pages

Free hosting for static sites. Push your build output to a gh-pages branch.

Performance Tips for Large Repositories

Shallow Clone (Download Less History)

# Clone only the latest commit
git clone --depth 1 https://github.com/user/repo.git

# Get more history later if needed
git fetch --unshallow

Sparse Checkout (Download Only Some Directories)

git clone --no-checkout https://github.com/user/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set src docs
git checkout main

Git LFS (Large File Storage)

For repos with binary assets (images, videos, models):

git lfs install
git lfs track "*.psd"
git lfs track "*.mp4"
git add .gitattributes

Security Best Practices

  1. Never commit secrets. Use .env files and add them to .gitignore.
  2. Use git secret or SOPS for encrypted secrets in repos.
  3. Enable branch protection on GitHub for main.
  4. Require PR reviews (at least 1 approval).
  5. Use signed commits (git commit -S) for important repos.
  6. Regularly audit .git for leaked secrets using tools like trufflehog or git-secrets.
  7. If you accidentally commit a secret, rotate it immediately. Don't just delete it — it's already in the history.

Conclusion

Git has a steep learning curve, but it rewards you with total control over your codebase. The commands in this guide cover 95% of what you'll encounter in daily work.

The 5 most important things to remember:

  1. Commit small, commit often. Small commits are easier to review, revert, and understand.
  2. Write meaningful commit messages. Future you will thank present you.
  3. Use branches for everything. Never commit directly to main.
  4. Learn to use git log --graph. Understanding your history prevents mistakes.
  5. When in doubt, git stash before doing anything risky.

Master Git early. It's the one tool you'll use every single day of your career.