Git Go Ahead

The free, no-fluff Git reference for developers. From your very first git init to advanced branching strategies — everything you need in one scrollable guide.

Scroll down to begin the Git tutorial

what is git?

Git is a free, open-source distributed version control system created by Linus Torvalds in 2005. It tracks changes to files over time so you can recall specific versions later, collaborate with others without overwriting each other's work, and confidently experiment knowing you can always roll back.

Unlike older centralised systems, every developer has a full copy of the entire project history on their local machine — making Git fast, offline-capable, and resilient.

why every developer needs git

Git vs GitHub vs GitLab

Git is the command-line tool that runs on your machine. GitHub and GitLab are cloud platforms that host Git repositories and add collaboration features (pull requests, issues, CI/CD). You need Git to use them, but Git works perfectly fine without them.

installation & setup

Download and install Git for your operating system. Git is free and available on all major platforms:

first-time configuration

After installing, tell Git who you are. This info is attached to every commit you make:

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

create a repository

A repository (repo) is the folder where Git tracks all your project files and history. Navigate to your project directory and run:

git init

This creates a hidden .git folder — Git's database for your project. Nothing is tracked yet; you decide which files to include.

check what git sees

git status

Your most-used command — shows staged, unstaged, and untracked files

git status -s

Short format — compact overview at a glance

Tip: initialise with a README

On GitHub/GitLab you can tick "Initialise with README" when creating a repo. Locally, just create the file yourself: echo "# My Project" > README.md then commit it as your first change.

.gitignore

A .gitignore file tells Git which files and folders to never track. Create one at the root of your repository before your first commit.

Common things to ignore: compiled binaries, dependency folders, secrets, and OS noise.

example .gitignore

# Dependencies
node_modules/
vendor/

# Build output
dist/
build/
*.o
*.class

# Secrets & environment
.env
.env.local
*.pem
*.key

# OS files
.DS_Store
Thumbs.db

# Editor metadata
.vscode/
.idea/
*.swp
touch .gitignore

Create the file at your project root

git rm --cached <file>

Stop tracking a file you already committed (then add it to .gitignore)

gitignore.io

Visit gitignore.io (or use the GitHub UI) to auto-generate a .gitignore tailored to your language and tools — Node, Python, Java, macOS, Windows, and hundreds more.

clone a repository

To work with an existing repository, clone it to get a full local copy — including all branches and history:

Clone from GitHub/GitLab (most common):

git clone https://github.com/username/repository.git

Clone into a specific folder name:

git clone https://github.com/username/repo.git my-folder

Clone from a local path:

git clone /path/to/repository

Shallow clone (faster, last commit only):

git clone --depth 1 https://github.com/username/repo.git

After cloning, the remote is automatically added as origin — so you can git push and git pull right away.

git's three trees

Git manages your code through three conceptual areas. Understanding this model makes every command click into place:

The workflow is: edit in your working directory → stage with git addcommit with git commit.

Diagram of Git's three-tree architecture: Working Directory, Staging Area (Index), and HEAD repository

stage & commit

Staging lets you craft precise, logical commits — even if your working directory has multiple unrelated changes in progress.

staging changes

git add <filename>

Stage a specific file

git add .

Stage all changes in the current directory

git add -p

Interactively stage individual hunks — great for keeping commits focused

committing changes

git commit -m "feat: add user authentication"

Commit staged changes with an inline message

git commit --amend

Rewrite the last commit (message or staged content) — only before pushing

Write commits your future self will thank you for

  • Explain the why, not just the what — the diff already shows what changed
  • Use the imperative mood: "Fix bug" not "Fixed bug"
  • Consider the Conventional Commits format: feat:, fix:, docs:, chore:
  • Keep the subject line under 72 characters
  • Commit early and often — small commits are easier to review and revert

push to remote

Share your committed changes with the world by pushing to a remote repository:

push to a branch

git push origin main

Replace main with your branch name. On first push of a new branch, use -u to set the upstream:

git push -u origin feature/my-branch

add a remote

If you initialised locally with git init, connect to a remote first:

git remote add origin <repository-url>

Link your local repo to a remote (e.g. GitHub)

git remote -v

Verify your remotes are configured correctly

Before you push

  • Pull latest changes first: git pull --rebase origin main
  • Run your tests — don't break the shared branch
  • Use descriptive branch names: feature/user-auth, fix/login-crash
  • Push feature branches early — it backs up your work and enables early feedback

branching

Branches are one of Git's killer features. They let you develop features, fix bugs, and experiment in complete isolation — without touching main until you're ready.

Git branching diagram showing the main branch with feature and bugfix branches merging back in

essential branch commands

git switch -c feature/new-feature

Create and switch to a new branch (modern syntax)

git checkout -b feature/new-feature

Older equivalent — also creates and switches

git branch

List all local branches (* marks the current one)

git branch -a

List all branches including remote-tracking branches

git switch main

Switch back to main

git branch -d feature/new-feature

Delete a fully merged branch (safe)

git branch -D feature/new-feature

Force delete — even if unmerged (use with care)

git push origin feature/new-feature

Push branch to remote for backup or code review

Branching best practices

  • Name branches clearly: feature/user-login, bugfix/header-overflow, hotfix/payment-null-check
  • Keep branches short-lived — big long-running branches are harder to merge
  • Regularly sync with main to minimise conflicts: git merge main
  • Delete merged branches to keep your repo tidy
  • Protect your main branch — require PRs and passing CI before merging

update & merge

Keep your branches in sync and integrate work from teammates:

update your local repository

git pull

Fetch remote changes and merge into your current branch

git fetch origin

Download remote changes without merging — lets you inspect first

git pull --rebase origin main

Replay your commits on top of the latest main (cleaner history)

merging branches

git merge <branch-name>

Integrates changes from another branch into your current one, preserving full history.

resolving merge conflicts

When Git can't automatically reconcile two sets of changes, it marks the conflict in the file and asks you to resolve it manually:

  1. Open the conflicted file — look for <<<<<<< and >>>>>>> markers
  2. Edit the file to keep the correct content and remove the markers
  3. Stage the resolved file: git add <filename>
  4. Complete the merge: git commit

preview changes before merging

git diff main feature/new-feature

Always compare branches before merging so there are no surprises.

Merge strategy tips

  • Use pull requests for all merges into main — enables code review
  • Run your full test suite after merging — never skip CI
  • Prefer git rebase for local feature branches to keep history linear
  • Use git merge --no-ff to always create a merge commit (preserves branch history)
  • Communicate with teammates before merging large changes

tagging releases

Tags are permanent labels on specific commits — the standard way to mark software releases and version milestones:

creating tags

git tag v1.0.0

Lightweight tag at the current commit

git tag -a v1.0.0 -m "Release version 1.0.0"

Annotated tag with a message — recommended for releases

git tag -a v1.0.0 1b2e1d63ff

Tag a specific past commit using its hash

managing and sharing tags

git tag

List all tags

git show v1.0.0

Show details about a tag and its commit

git push origin v1.0.0

Push a specific tag to remote

git push origin --tags

Push all local tags to remote

git tag -d v1.0.0

Delete a tag locally

Use Semantic Versioning

Follow MAJOR.MINOR.PATCH (e.g. v2.1.3): bump MAJOR for breaking changes, MINOR for new backwards-compatible features, PATCH for bug fixes. This communicates the impact of a release clearly.

viewing history

Git's log commands let you explore your project's entire history, understand what changed, and find specific commits:

basic log commands

git log

Full commit history with author, date, and message

git log --oneline

Compact one-line format — great for scanning history

git log --author="Jane Doe"

Filter commits by a specific author

git log --since="2 weeks ago"

Show commits within a time range

git log --grep="fix"

Search commit messages for a keyword

visualise your branch graph

git log --graph --oneline --decorate --all

ASCII art tree of all branches — see merges and divergences at a glance

git log --name-status

Show which files were added, modified, or deleted per commit

git log --stat

Show insertion/deletion statistics per file per commit

git log -p <filename>

Full diff history for a single file

git blame <filename>

See who last modified each line of a file

For the full reference: git log --help

undo changes

Git gives you multiple ways to undo mistakes — choose the right tool based on how far along the change has gone:

discard unstaged changes

git restore <filename>

Discard changes in working directory (modern syntax)

git restore .

Discard ALL unstaged changes — cannot be undone

unstage a file

git restore --staged <filename>

Moves a file out of the staging area without losing your edits.

undo commits

git reset --soft HEAD~1

Undo the last commit — keep changes staged and ready to re-commit

git reset HEAD~1

Undo the last commit — unstage changes but keep them in working directory

git revert <commit-hash>

Create a new commit that undoes a past commit — safe for shared branches

temporarily save work with stash

git stash

Shelve uncommitted changes to a temporary stack

git stash pop

Restore and remove the most recent stash

git stash list

See all stashed changesets

git stash apply stash@{2}

Apply a specific stash without removing it

Safety checklist before resetting

  • Run git status and git diff to understand what will be lost
  • git reset --hard permanently discards uncommitted changes — there is no undo
  • Prefer git revert over git reset on any branch shared with others
  • When in doubt, create a backup branch first: git branch backup/my-work

advanced tips

Level up your daily Git workflow with these productivity commands and configuration tricks:

essential configuration

git config --global color.ui auto

Coloured output — makes reading diffs and status much easier

git config --global core.editor "code --wait"

Set VS Code as your default Git editor

git config --global pull.rebase true

Rebase instead of merge on pull — keeps history linear by default

git config --global rerere.enabled true

Remember resolved merge conflicts and reapply them automatically

time-saving aliases

git config --global alias.st "status -s" git config --global alias.co checkout git config --global alias.br "branch -a" git config --global alias.last "log -1 HEAD --stat" git config --global alias.lg "log --oneline --graph --decorate --all"

After setting aliases, use git lg, git st, etc.

powerful one-liners

git commit -am "Quick fix"

Stage all tracked files and commit in one command

git cherry-pick <commit-hash>

Apply a single commit from another branch onto your current branch

git bisect start

Begin a binary search through history to find which commit introduced a bug

git shortlog -sn

Summarise commits per author — useful for team reporting

git clean -fd

Remove all untracked files and directories (irreversible — use with caution)

git gui tools

gitk --all

Built-in graphical history browser. Pairs well with GUI clients like GitKraken, Sourcetree, or the VS Code Git extension for visual diffs.

frequently asked questions

Answers to the questions every developer eventually Googles.

What is the difference between Git and GitHub?

Git is the version control tool that runs on your local machine — it tracks file history, manages branches, and handles merges. GitHub is a cloud platform that hosts Git repositories online and adds collaboration features: pull requests, issues, code review, CI/CD, and more. You can use Git without GitHub, but GitHub requires Git. GitLab and Bitbucket are popular alternatives to GitHub.

What is the difference between git pull and git fetch?

git fetch downloads new commits and branches from the remote but does not touch your working directory or current branch — it's safe and non-destructive. git pull is git fetch followed by git merge (or git rebase if configured). Use fetch when you want to inspect what changed before integrating it.

How do I undo my last commit without losing my changes?

Run git reset --soft HEAD~1 — this undoes the commit but leaves your changes staged and ready to re-commit. Use git reset HEAD~1 (mixed mode) to unstage the changes but keep them in your working directory. Only use git reset --hard HEAD~1 if you want to permanently discard the changes.

Should I use git merge or git rebase?

Use merge for integrating finished branches into main — it preserves the complete history and makes collaboration auditable. Use rebase to keep your local feature branch up-to-date with main before merging — it produces a clean, linear history without noisy merge commits. The golden rule: never rebase commits that have already been pushed to a shared branch.

What is a pull request (PR)?

A pull request is a feature of GitHub, GitLab (called Merge Request), and Bitbucket. It's a formal proposal to merge one branch into another, providing a structured space for teammates to review your code, leave comments, suggest changes, and run automated checks — before anything lands in main. PRs are the backbone of professional collaborative development.

How do I fix a detached HEAD state?

A detached HEAD means you've checked out a specific commit rather than a branch — any commits you make won't belong to any branch and can be lost. To save your work, create a branch from this point: git switch -c my-rescue-branch. To simply get back to where you were: git switch main.

resources & tools

Go deeper with these carefully curated tools, references, and interactive guides:

recommended git GUI clients

essential learning resources

advanced topics to explore next