Backend Tech Productivity

Git & GitHub Complete Guide: From Zero to Production Workflow

Every professional developer uses Git every single day — yet most tutorials only scratch the surface. This guide covers Git and GitHub end-to-end: from installing Git on your machine and making your first commit, all the way to the branching strategies and pull-request workflows used in real production teams. No prior version control experience is required.

Git vs GitHub — What's the Difference?

This is the most common point of confusion for beginners. They are two entirely different things:

  • Git is a free, open-source version control system that runs locally on your machine. It tracks changes to your files over time and lets you travel back to any previous state.
  • GitHub is a cloud platform that hosts Git repositories remotely, adds a web UI, and provides collaboration features like Pull Requests, Issues, and Actions. GitLab and Bitbucket are popular alternatives.
Think of Git as the engine and GitHub as the garage — you can drive without the garage, but the garage makes it far easier to collaborate and ship.

Step 1 — Install Git & First-Time Setup

Download Git from git-scm.com (Windows installer) or install via your package manager:

# macOS (Homebrew)
brew install git

# Ubuntu / Debian
sudo apt update && sudo apt install git -y

# Fedora / RHEL
sudo dnf install git -y

After installation, tell Git who you are. These values are stamped on every commit you make:

git config --global user.name  "Your Name"
git config --global user.email "you@example.com"

# Set VS Code as the default editor (optional but recommended)
git config --global core.editor "code --wait"

# Verify your config
git config --list

Step 2 — Core Concepts You Must Understand

Before running any commands, lock in these four concepts — everything else builds on them:

Repository (repo)

A repository is the folder Git is tracking. It contains your project files plus a hidden .git/ directory where Git stores the entire history. There are two kinds: a local repo on your machine and a remote repo on GitHub.

Commit

A commit is a snapshot of your files at a specific moment in time. Every commit has a unique SHA hash (e.g., a3f8c21), an author, a timestamp, and a message. Git history is just a chain of commits.

Branch

A branch is a lightweight, movable pointer to a commit. The default branch is called main (or master in older repos). Creating a branch lets you develop a feature in isolation without touching stable code.

Staging Area (Index)

The staging area is a preparation zone between your working directory and a commit. You explicitly choose which changes to stage with git add before sealing them into a commit with git commit. This gives you fine-grained control over what goes into each snapshot.

Step 3 — Start a Repository

There are two ways to get a local Git repository:

Option A — Initialise a new project

# Create a folder and enter it
mkdir my-project && cd my-project

# Initialise Git
git init

# You'll see: Initialized empty Git repository in .../my-project/.git/

Option B — Clone an existing remote repo

# Clone over HTTPS (easiest for beginners)
git clone https://github.com/username/repository-name.git

# Clone over SSH (recommended for daily use — no password prompts)
git clone git@github.com:username/repository-name.git

# Clone then immediately enter the folder
git clone https://github.com/username/repo.git && cd repo

Step 4 — The Daily Git Loop

Every working day with Git follows the same rhythm: check what changed, stage what you want, commit it, and push to the remote. Here's the full flow with every command you'll use:

Check the state of your working tree

# See which files are modified, staged, or untracked
git status

# See the actual line-by-line diff of unstaged changes
git diff

# See the diff of what's already staged (about to be committed)
git diff --staged

Stage changes

# Stage a specific file
git add src/app.js

# Stage multiple files
git add src/app.js src/utils.js

# Stage all changes in the current directory (use carefully)
git add .

# Stage parts of a file interactively (powerful — lets you split one file into multiple commits)
git add -p src/app.js

Commit staged changes

# Commit with an inline message
git commit -m "feat: add user authentication endpoint"

# Open your editor to write a multi-line commit message
git commit

# Stage all tracked files AND commit in one step (skips untracked files)
git commit -am "fix: correct off-by-one error in pagination"

View history

# Full log
git log

# Compact one-line-per-commit view
git log --oneline

# Visualise branches as a graph
git log --oneline --graph --all --decorate

# Show what changed in a specific commit
git show a3f8c21

Push & pull from GitHub

# Push your local branch to the remote (first time: set upstream)
git push -u origin main

# Push subsequent commits (once upstream is set)
git push

# Fetch remote changes and merge them into your current branch
git pull

# Fetch without merging (inspect changes before integrating)
git fetch origin

Step 5 — Branching & Merging

Branches are where Git gets powerful. The golden rule: never commit directly to main. Always work on a feature branch and merge it in when it's ready.

Create and switch branches

# Create a new branch
git branch feature/login-page

# Switch to it
git checkout feature/login-page

# Create AND switch in one command (modern shorthand)
git switch -c feature/login-page

# List all local branches (* marks the current one)
git branch

# List remote branches too
git branch -a

Merge a branch into main

# Switch to the branch you want to merge INTO
git switch main

# Pull the latest remote changes first (important!)
git pull origin main

# Merge your feature branch
git merge feature/login-page

# Delete the branch once merged (keeps things tidy)
git branch -d feature/login-page

# Delete the remote branch too
git push origin --delete feature/login-page

Rebase (a cleaner alternative to merge)

# While on your feature branch, replay its commits on top of main
git switch feature/login-page
git rebase main

# Interactive rebase — reorder, squash, or edit the last 3 commits
git rebase -i HEAD~3
Merge vs Rebase: merge preserves history exactly as it happened (good for shared branches). rebase rewrites history for a cleaner, linear log (good for local feature branches before a PR). Never rebase commits that have already been pushed and shared.

Step 6 — Undoing Mistakes

Git's superpower is that almost nothing is permanent. Here's your rescue toolkit:

Undo before committing

# Discard unstaged changes in a file (destructive — cannot be undone)
git restore src/app.js

# Unstage a file (keeps your changes, just removes from staging area)
git restore --staged src/app.js

Undo after committing

# Create a new commit that reverses a previous commit (safe for shared history)
git revert a3f8c21

# Move HEAD back N commits, keep changes staged
git reset --soft HEAD~1

# Move HEAD back N commits, keep changes unstaged
git reset --mixed HEAD~1

# Move HEAD back N commits and DISCARD all changes (destructive)
git reset --hard HEAD~1

Stash work in progress

# Save dirty working tree without committing
git stash

# Give the stash a descriptive name
git stash push -m "WIP: half-done login form"

# List all stashes
git stash list

# Apply the most recent stash and keep it in the list
git stash apply

# Apply AND remove from the list
git stash pop

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

Step 7 — The .gitignore File

A .gitignore file tells Git which files and folders to never track. You should always create one at the project root before your first commit.

# ── .gitignore example for a Node.js project ──

# Dependencies
node_modules/

# Build output
dist/
build/
.next/

# Environment variables (NEVER commit secrets)
.env
.env.local
.env.*.local

# OS noise
.DS_Store
Thumbs.db

# Editor settings
.vscode/
.idea/
*.swp

# Logs
*.log
npm-debug.log*
Pro tip: Use gitignore.io to generate a .gitignore tailored to your language and IDE in seconds. Commit the .gitignore as the very first file in every new project.

Step 8 — GitHub: Remotes, Forks & Pull Requests

GitHub layers collaboration on top of Git. Here's the complete open-source contribution and team workflow:

Connect a local repo to GitHub

# Add GitHub as a remote named "origin"
git remote add origin https://github.com/username/repo.git

# Verify remotes
git remote -v

# Push for the first time and set the upstream tracking branch
git push -u origin main

SSH key setup (do this once — saves typing your password forever)

# Generate an Ed25519 key (modern, preferred over RSA)
ssh-keygen -t ed25519 -C "you@example.com"

# Start the SSH agent and add your key
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519

# Copy the public key to your clipboard
# macOS:
cat ~/.ssh/id_ed25519.pub | pbcopy
# Linux:
cat ~/.ssh/id_ed25519.pub | xclip -selection clipboard

# Paste it into: GitHub → Settings → SSH and GPG keys → New SSH key

Fork → Clone → PR (open-source workflow)

  1. On GitHub, click Fork on the repo you want to contribute to — this copies it to your account.
  2. Clone your fork locally: git clone git@github.com:your-username/repo.git
  3. Add the original repo as upstream so you can sync updates: git remote add upstream git@github.com:original-owner/repo.git
  4. Create a feature branch: git switch -c fix/typo-in-readme
  5. Make your changes, stage, and commit them.
  6. Push to your fork: git push -u origin fix/typo-in-readme
  7. Go to GitHub and click Compare & pull request. Write a clear description and submit.
  8. Respond to review comments, push additional commits — the PR updates automatically.
  9. Once approved, a maintainer merges your PR. Your contribution is live!

Sync your fork with the original

# Fetch changes from the original repo
git fetch upstream

# Merge them into your local main
git switch main
git merge upstream/main

# Push the updated main to your fork
git push origin main

Step 9 — Writing Great Commit Messages

A well-written commit message is a gift to your future self and your teammates. The most widely adopted convention is Conventional Commits:

<type>(<optional scope>): <short summary in present tense>

<optional body — explain WHY, not WHAT>

<optional footer — e.g. "Closes #42">

Common types and when to use them:

  • feat — a new feature visible to users
  • fix — a bug fix
  • docs — documentation changes only
  • style — formatting, missing semicolons — no logic change
  • refactor — code change that neither fixes a bug nor adds a feature
  • test — adding or updating tests
  • chore — build process, dependency updates, tooling
  • perf — performance improvement

Real examples — bad vs good:

# Bad — tells you nothing
git commit -m "fix stuff"
git commit -m "update"
git commit -m "wip"

# Good — clear, scannable, professional
git commit -m "fix(auth): prevent session token from expiring prematurely"
git commit -m "feat(api): add paginated /users endpoint"
git commit -m "chore(deps): upgrade axios from 1.4.0 to 1.7.2"
git commit -m "docs: add SSH setup instructions to README"

Step 10 — Professional Git Branching Strategy

Individual projects can get away with a simple branch-per-feature approach. Teams typically adopt one of two strategies:

GitHub Flow (simple — ideal for CI/CD teams)

main                  ← always deployable, protected
  └── feature/X       ← your work
  └── fix/Y           ← a bug fix
  └── chore/Z         ← tooling change
  1. Create a branch from main.
  2. Commit often, push often.
  3. Open a PR when ready for review.
  4. Merge to main after approval — this triggers automated deployment.

Git Flow (structured — ideal for release-based products)

main                  ← production releases only (tagged v1.0, v1.1, …)
develop               ← integration branch — all features merge here
  └── feature/login   ← new feature
  └── feature/search  ← another feature
release/1.2           ← pre-release stabilisation branch
hotfix/1.1.1          ← urgent production bug fix (branches from main)
Which to choose? Start with GitHub Flow — it's simpler and works for most modern teams that deploy continuously. Switch to Git Flow only if you manage multiple concurrent release versions.

Step 11 — GitHub Actions (CI/CD in 60 Seconds)

GitHub Actions lets you automate workflows — run tests on every push, lint on every PR, or deploy on every merge to main. Workflows live in .github/workflows/ as YAML files.

# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linter
        run: npm run lint

      - name: Run tests
        run: npm test

Once this file is committed, every push and pull request will trigger the workflow. GitHub shows a green checkmark or red cross directly on the PR — reviewers can see at a glance whether the tests pass.

Useful Git Commands Cheat Sheet

# ── Repository ──────────────────────────────────────
git init                        # create a new local repo
git clone <url>                 # clone a remote repo

# ── Staging & Committing ──────────────────────────
git status                      # show working tree status
git diff                        # unstaged changes
git diff --staged               # staged changes
git add <file>                  # stage a file
git add .                       # stage everything
git commit -m "message"         # commit with message
git commit --amend              # edit the last commit (local only!)

# ── Branches ──────────────────────────────────────
git branch                      # list local branches
git switch -c <branch>          # create + switch
git switch <branch>             # switch branch
git merge <branch>              # merge into current
git rebase <branch>             # rebase onto branch
git branch -d <branch>          # delete merged branch

# ── Remote ────────────────────────────────────────
git remote -v                   # list remotes
git remote add origin <url>     # add remote
git push -u origin <branch>     # push + set upstream
git push                        # push current branch
git pull                        # fetch + merge
git fetch                       # fetch only

# ── Undoing ───────────────────────────────────────
git restore <file>              # discard unstaged changes
git restore --staged <file>     # unstage a file
git revert <sha>                # safe undo (new commit)
git reset --soft HEAD~1         # undo commit, keep staged
git reset --hard HEAD~1         # undo commit, discard changes

# ── Stash ─────────────────────────────────────────
git stash                       # save WIP
git stash pop                   # restore latest WIP
git stash list                  # list all stashes

# ── Inspection ────────────────────────────────────
git log --oneline --graph --all # visual branch history
git blame <file>                # who changed which line
git bisect start                # binary search for a bug
git shortlog -sn                # top contributors by commit count

Key Takeaways

  • Git is local version control; GitHub is the cloud platform that hosts it and adds collaboration tools.
  • The core daily loop is: git pull → make changes → git addgit commitgit push.
  • Always work on a feature branch — never commit directly to main.
  • Write Conventional Commit messages: type(scope): summary. Future-you will thank present-you.
  • A .gitignore committed at project creation prevents secrets and build artefacts from ever entering history.
  • git revert is the safe way to undo shared history; git reset --hard is a last resort on local-only commits.
  • GitHub Actions can automate tests, linting, and deployment with a single YAML file — add it early.
  • SSH keys eliminate password prompts — set them up once and forget about them.

What's Next?

You now have the complete toolkit for working with Git and GitHub like a professional. The next steps are practice and muscle memory — the commands will become second nature within a week of daily use.

From here, explore GitHub Issues for project management, GitHub Projects (kanban boards built into your repo), and GitHub Packages for publishing libraries. On the Git side, dig deeper into git bisect for hunting bugs across history, and git worktree for maintaining multiple checked-out branches simultaneously without cloning twice.

Check out the archive for more backend and DevOps guides, or reach out via the contact page — always happy to help you level up your workflow.

Dhiraj Roy
Dhiraj Roy

Backend developer & tech writer. Writing about Java, Spring Boot, Python, and AI at Digital Drift.