Git on Linux: The Complete Guide for Beginners and Beyond

Git on Linux: The Complete Guide for Beginners and Beyond

Tested on: Ubuntu 26.04 LTS · Debian 12 · Fedora 44 · Arch Linux — Last updated: June 2026

Git was written by Linus Torvalds in 2005 to manage the Linux kernel — the most complex software project on earth. Today it underpins virtually every codebase, from solo hobby projects to large distributed teams. If you're working on Linux, Git is a first-class citizen: it ships in every major distro's package manager, integrates cleanly with SSH keys, and pairs naturally with shell scripting. This guide takes you from installation through real workflows, covering branching, remotes, rebasing, undoing mistakes, and the commands you'll use every single day.

Contents
  1. Prerequisites
  2. Install Git
  3. Initial Configuration
  4. Core Concepts: The Three Areas
  5. Create Your First Repository
  6. Staging and Committing
    1. Writing Good Commit Messages
  7. Viewing History
  8. Branches
  9. Merging and Rebasing
    1. Merging
    2. Rebasing
  10. Working with Remotes
  11. SSH Keys for GitHub and GitLab
  12. Undoing Changes
  13. .gitignore
    1. Further Reading

Prerequisites

  • A Linux terminal with sudo access (Ubuntu, Debian, Fedora, Arch, or compatible)
  • Basic familiarity with the command line — navigating directories, creating files
  • A GitHub or GitLab account if you want to follow the remote/SSH sections

Install Git

Git is available in every major distro's default repositories. Install it with your package manager:

# Ubuntu / Debian:
sudo apt update && sudo apt install git

# Fedora:
sudo dnf install git

# Arch Linux:
sudo pacman -S git

# openSUSE:
sudo zypper install git

# Verify the installed version:
git --version

Expected output:

git version 2.45.2

If you need a newer version than your distro ships, on Ubuntu/Debian you can add the official Git PPA:

sudo add-apt-repository ppa:git-core/ppa
sudo apt update && sudo apt install git

Initial Configuration

Before making any commits, Git needs to know who you are. This information is embedded in every commit you make — it cannot be changed after the fact without rewriting history.

# Set your identity — use the email tied to your GitHub/GitLab account:
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Default branch name for new repositories (modern standard):
git config --global init.defaultBranch main

# Set your preferred editor for commit messages:
git config --global core.editor nano     # or: vim, nvim, code --wait, etc.

# Define what 'git pull' does by default (merge, not rebase):
git config --global pull.rebase false

# Enable colored output:
git config --global color.ui auto

# Helpful diff algorithm (better at detecting moved code):
git config --global diff.algorithm histogram

# Verify your settings:
git config --list --global

# Config is stored at:
cat ~/.gitconfig

Your ~/.gitconfig will look like this:

[user]
    name = Your Name
    email = you@example.com
[init]
    defaultBranch = main
[core]
    editor = nano
[pull]
    rebase = false
[color]
    ui = auto
[diff]
    algorithm = histogram

Core Concepts: The Three Areas

Every confusion about Git traces back to not understanding these three areas:

  • Working Directory — the files you see and edit on disk. This is your live, messy work-in-progress state.
  • Staging Area (Index) — a curated snapshot of changes you've explicitly selected for the next commit. You control exactly what goes in using git add.
  • Repository (.git/) — the permanent database of all commits, branches, tags, and history. Lives in the hidden .git/ folder in your project root.

The flow is always: edit files in the Working Directory → git add moves changes into the Staging Area → git commit saves the staged snapshot permanently into the Repository.

Create Your First Repository

# Initialize a new repository in an existing directory:
mkdir myproject && cd myproject
git init
# Output: Initialized empty Git repository in /home/user/myproject/.git/

# Clone an existing remote repository (HTTPS):
git clone https://github.com/username/reponame.git

# Clone via SSH (requires SSH key setup — see below):
git clone git@github.com:username/reponame.git

# Clone into a specific directory name:
git clone git@github.com:username/reponame.git my-local-name

# After cloning, Git automatically configures 'origin' as the remote.

Staging and Committing

# Create a file and check status:
echo "# My Project" > README.md
git status
# Output:
# On branch main
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#         README.md

# Stage a specific file:
git add README.md

# Stage everything in the current directory:
git add .

# Stage interactively — review and select individual hunks:
git add -p

# See what's staged vs what's still unstaged:
git diff              # changes NOT yet staged
git diff --staged     # changes staged and ready to commit

# Commit with an inline message:
git commit -m "docs: add initial README"

# Commit and open your editor for a longer message:
git commit

Writing Good Commit Messages

Your commit messages are the primary documentation for why code changed. Write for your future self debugging a problem at 2am.

# Bad — useless in git log:
git commit -m "fix"
git commit -m "changes"
git commit -m "wip"

# Good — self-documenting:
git commit -m "Fix login form not clearing password field after failed attempt"
git commit -m "Add rate limiting to /api/auth endpoints (100 req/min)"

# Conventional Commits format (widely adopted standard):
git commit -m "feat: add JWT refresh token rotation"
git commit -m "fix: resolve null pointer in user profile loader"
git commit -m "docs: update API authentication examples"
git commit -m "refactor: extract payment processing into service class"
git commit -m "chore: upgrade dependencies to latest patch versions"

Viewing History

# Full log:
git log

# Compact, one line per commit:
git log --oneline

# Visual branch graph across all branches:
git log --oneline --graph --all

# Filter by author:
git log --author="Jane"

# Search commit messages:
git log --grep="rate limit"

# Show commits affecting a specific file:
git log -- src/auth.py

# Show full diff of a specific commit:
git show a3f8c12

# Annotate a file — who last changed each line:
git blame src/auth.py

# Binary search to find which commit introduced a bug:
git bisect start
git bisect bad                  # current state is broken
git bisect good v1.2.0          # this tag/commit was working
# Git checks out the midpoint — test it, then mark:
git bisect good                 # or: git bisect bad
# Repeat until Git identifies the culprit commit
git bisect reset                # return to HEAD when done

Branches

Branches are lightweight pointers to commits. Creating one is instantaneous. Use them freely — one branch per feature, per bug fix, per experiment.

# List local branches (* marks current):
git branch

# List all branches including remotes:
git branch -a

# Create and switch to a new branch (two equivalent forms):
git checkout -b feature/user-auth
git switch -c feature/user-auth       # modern syntax (Git 2.23+)

# Switch to an existing branch:
git switch main

# Delete a merged branch:
git branch -d feature/user-auth

# Force-delete an unmerged branch:
git branch -D feature/user-auth

# Rename the current branch:
git branch -m better-name

# Push a new branch to remote and set upstream tracking:
git push -u origin feature/user-auth

Merging and Rebasing

Merging

Merging joins two branch histories. It creates a merge commit that preserves the full record of when work diverged and rejoined — honest history.

# Merge a feature branch into main:
git switch main
git merge feature/user-auth

# When there are conflicts, Git marks them in the affected files:
# <<<<<<< HEAD
# your version on main
# =======
# incoming version from feature/user-auth
# >>>>>>> feature/user-auth

# Edit each file to resolve the conflict, then:
git add resolved-file.py
git commit    # Git pre-fills the merge commit message

# Changed your mind mid-merge:
git merge --abort

Rebasing

Rebasing replays your commits on top of another branch, producing a clean linear history with no merge commits. Use it on private feature branches before merging — never on branches others have already pulled.

# Rebase your feature branch onto the latest main:
git switch feature/user-auth
git rebase main

# Conflicts during rebase: edit, add, then continue:
git add resolved-file.py
git rebase --continue

# Abort a rebase in progress:
git rebase --abort

# Interactive rebase — squash, reorder, edit, or drop commits:
git rebase -i HEAD~4    # edit the last 4 commits

# In the editor, change 'pick' to:
# squash (s)  — merge into previous commit
# reword (r)  — change the commit message
# drop (d)    — delete the commit entirely
# edit (e)    — stop and amend the commit

Working with Remotes

# Add a remote (standard name is 'origin'):
git remote add origin https://github.com/username/repo.git

# View configured remotes:
git remote -v
# origin  git@github.com:username/repo.git (fetch)
# origin  git@github.com:username/repo.git (push)

# First push — sets upstream tracking branch:
git push -u origin main

# Push subsequent commits:
git push

# Pull (fetch + merge into current branch):
git pull

# Fetch changes without merging (safe to inspect first):
git fetch origin
git log origin/main --oneline    # see what's there
git merge origin/main            # integrate when ready

# Push a feature branch:
git push -u origin feature/user-auth

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

# Change remote URL (e.g., HTTPS → SSH):
git remote set-url origin git@github.com:username/repo.git

SSH Keys for GitHub and GitLab

SSH key authentication eliminates password prompts and is more secure than HTTPS with a stored password. If most of your workflow is on GitHub specifically, GitHub CLI can generate and upload this key for you as part of gh auth login, skipping the manual steps below.

# Generate a new ED25519 key (preferred algorithm):
ssh-keygen -t ed25519 -C "you@example.com"
# Accept default path (~/.ssh/id_ed25519), set a passphrase

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

# Print your public key — copy this entire line:
cat ~/.ssh/id_ed25519.pub

# Add to GitHub:  Settings → SSH and GPG keys → New SSH key → paste
# Add to GitLab:  Preferences → SSH Keys → paste

# Test authentication:
ssh -T git@github.com
# Hi username! You've successfully authenticated, but GitHub does
# not provide shell access.

ssh -T git@gitlab.com
# Welcome to GitLab, @username!

To persist the SSH agent across reboots on systemd-based systems, add the following to your ~/.bashrc or ~/.bash_profile:

if [ -z "$SSH_AUTH_SOCK" ]; then
  eval "$(ssh-agent -s)"
  ssh-add ~/.ssh/id_ed25519
fi

Undoing Changes

This is where Git saves you. Knowing these commands removes the fear of experimenting.

SituationCommand
Unstage a file (keep changes on disk)git restore --staged filename
Discard working directory changesgit restore filename
Undo last commit, keep changes stagedgit reset --soft HEAD~1
Undo last commit, keep changes unstagedgit reset HEAD~1
Undo last commit and discard changesgit reset --hard HEAD~1
Safely undo a pushed commitgit revert abc1234
Fix the last commit messagegit commit --amend -m "corrected message"
Add a forgotten file to last commitgit add file && git commit --amend --no-edit
Stash work-in-progress temporarilygit stash / git stash pop
List all stashesgit stash list

Rule of thumb: git revert is always safe on shared branches — it adds a new commit. git reset --hard destroys history and should only be used on local commits you haven't pushed.

.gitignore

The .gitignore file lists patterns for files Git should never track. Create it in the root of your repository and commit it.

# Python project:
__pycache__/
*.pyc
*.pyo
.env
venv/
.venv/
*.egg-info/
dist/
build/
.pytest_cache/

# Node.js project:
node_modules/
npm-debug.log*
.env
dist/
.next/

# OS artifacts:
.DS_Store
Thumb


Go up

This site uses cookies for analytics and advertising (Google AdSense). By continuing to browse, you accept our use of cookies. Learn more