A quick-reference for Git version control. Git tracks changes as a directed acyclic graph of commits; each commit is a snapshot, not a diff. The working tree, staging area (index), and repository are the three layers you move changes through.
The everyday workflow: initialise or clone a repo, stage changes, commit, and repeat. Stage only what belongs in a commit — git add -p lets you stage hunks interactively.
git init # create new repo in current dir
git clone https://github.com/user/repo.git
git clone repo.git mydir # clone into custom directory
git status # show working tree state
git add file.txt # stage a file
git add -p # interactively stage hunks
git add . # stage all changes in current dir
git commit -m "message"
git commit -am "message" # stage all tracked files + commit
git commit --amend # edit last commit message (local only)
git commit --amend --no-edit # amend last commit, keep message
git diff # unstaged changes
git diff --staged # staged changes vs last commit
Branches are just pointers to commits — they're cheap to create. Prefer git switch and git restore over git checkout for clarity (available since Git 2.23).
git switch -c feature/my-feature # create + switch
git switch main # switch to existing branch
git branch # list local branches
git branch -a # list all (including remote)
git branch -d feature/done # delete merged branch
git branch -D feature/unmerged # force delete
git merge feature/my-feature # merge into current branch
git merge --no-ff feature/my-feature # always create merge commit
git merge --abort # abort a conflicted merge
git rebase main # rebase current branch onto main
git rebase -i HEAD~3 # interactive: squash/edit last 3 commits
git rebase --abort
Never rebase commits that have been pushed to a shared branch.
git cherry-pick <commit-hash>
Apply the changes from a specific commit onto the current branch.
Stage your correction, then create a fixup commit targeting the SHA you want to amend:
git add file.txt
git commit --fixup=<sha> # creates a commit named "fixup! <original message>"
Then replay history so the fixup is squashed in automatically, skipping the editor:
GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash <parent-of-sha>
--autosquash moves the fixup commit next to its target and sets the action to fixup (squashes silently, discarding the fixup message). GIT_SEQUENCE_EDITOR=true accepts the rebase plan as-is without opening an editor. Rewrites history — only use on local / unshared commits.
Remotes are named references to other repositories. origin is the conventional name for the repo you cloned from.
git fetch origin # download without merging
git pull # fetch + merge (or rebase with --rebase)
git pull --rebase # apply remote changes before local commits
git push origin main
git push -u origin my-branch # push + set upstream tracking
git push --force-with-lease # safer force push; fails if remote has new commits
git remote -v # list remotes
git remote add upstream https://github.com/orig/repo.git
git remote set-url origin git@github.com:user/repo.git
git tag v1.0.0 # lightweight tag
git tag -a v1.0.0 -m "Release 1.0.0" # annotated tag
git push origin v1.0.0 # push a tag
git push origin --tags # push all tags
Navigating history. git log --oneline --graph gives a compact visual overview of the branch topology.
git log --oneline
git log --oneline --graph --all
git log -p file.txt # commits + diffs for a file
git log --author="Name"
git log --since="2 weeks ago"
git diff main..feature # between two branches
git diff HEAD~2 # vs 2 commits ago
git show abc1234 # show a specific commit
git blame file.txt
Shows the commit and author for each line.
git bisect start
git bisect bad
git bisect good v1.0
git bisect reset # finish and return to HEAD
Binary search through history; Git checks out the midpoint commit each step.
git reflog
Shows a log of all HEAD movements; use it to recover "lost" commits or branches after a bad reset.
Three distinct tools depending on what you want to preserve. revert is the safe option for shared branches — it creates a new commit rather than rewriting history.
git restore file.txt # discard unstaged changes in a file
git restore . # discard all unstaged changes
git restore --staged file.txt # unstage (keep working tree changes)
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
Never use --hard or force-push on shared/published commits.
git revert abc1234
Creates a new commit that undoes the specified commit.
git clean -n # dry run — show what would be removed
git clean -fd # remove untracked files and directories
Stash saves uncommitted changes to a stack so you can switch context and come back later.
git stash # stash working tree + index
git stash -u # also stash untracked files
git stash push -m "description" # stash with a label
git stash pop # apply most recent stash + remove it
git stash apply stash@{2} # apply without removing
git stash list
git stash drop stash@{0} # delete a specific stash
Worktrees let you check out multiple branches simultaneously, each in its own directory, all linked to the same repository. Useful for working on a feature while fixing a bug on main without stashing or switching branches.
git worktree add ../hotfix main # check out 'main' in a new folder
git worktree add ../feature -b feature/new # new branch in new folder
git worktree list # show all linked worktrees
git worktree remove ../hotfix # remove a worktree
git worktree prune # clean up stale .git metadata
Git config is layered: --system (all users), --global (current user), --local (this repo). Local overrides global overrides system.
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --list --show-origin
Shows each setting alongside the file it was set in.
git config --global core.editor "nvim"
git config --global pull.rebase true # rebase on pull instead of merge
git config --global push.autoSetupRemote true # auto -u on first push
git config --global init.defaultBranch main
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.unstage "restore --staged"