Git

Complete Git cheat sheet covering core concepts, branching, merging, rebasing, undoing changes, workflows, and common interview patterns.

10 sections22 cards

Core concepts

Git is a distributed version control system. Every clone is a full copy of the repository — no single point of failure.

Three areas of a Git project:

Working directory — files you're actively editing.

Staging area (index) — snapshot of what will go into the next commit. git add moves changes here.

Repository (.git) — permanent history of commits.

Git stores snapshots, not diffs. Each commit is a full snapshot of the project at that point. Git is efficient — unchanged files are stored as references to previous snapshots.

Objects model

Git has 4 object types, all content-addressed by SHA-1 hash:

Blob — file content.

Tree — directory listing (points to blobs and other trees).

Commit — points to a tree + parent commit(s) + author/message.

Tag — points to a commit with a label.

A branch is just a pointer (file containing a SHA) to a commit. HEAD is a pointer to the current branch or commit. This is why branching in Git is instant and cheap.

Configuration

git config --global user.name 'Your Name'

git config --global user.email 'you@example.com'

git config --global core.editor 'code --wait' — set VS Code as editor.

git config --global init.defaultBranch main — default branch name.

git config --list — see all config.

Config levels: --system (all users), --global (current user), --local (current repo). Local overrides global overrides system.

.gitignore — list files/patterns to never track. node_modules/, .env, dist/. Global gitignore: git config --global core.excludesfile ~/.gitignore_global

Starting & staging

git init — initialize new repo in current directory.

git clone <url> — clone remote repo. git clone <url> folder-name — clone into specific folder.

git status — show working tree status. Use constantly.

git add <file> — stage specific file.

git add . — stage all changes in current directory.

git add -p — interactively stage chunks. Review each hunk before staging. Very useful.

git diff — unstaged changes. git diff --staged — staged changes (what's going into next commit).

Committing

git commit -m 'message' — commit staged changes.

git commit -am 'message' — stage all tracked files and commit. Skips git add for already-tracked files.

git commit --amend — modify the last commit (message or content). Only do this before pushing — rewrites history.

Good commit message format: imperative mood, under 72 chars, describe what and why not how. Add user authentication not Added auth stuff.

git log — commit history. git log --oneline — compact. git log --oneline --graph --all — visual branch graph.

Inspecting

git show <commit> — show commit details and diff.

git diff <branch1>..<branch2> — diff between branches.

git blame <file> — show who changed each line and when.

git log --follow <file> — history of a file including renames.

git log -S 'searchterm' — find commits that added/removed a string. Pickaxe search.

git log --author='Name' — filter by author.

git shortlog -sn — contributor summary by commit count.

Branch commands

git branch — list local branches. -a includes remote. -v shows last commit.

git branch <name> — create branch at current HEAD.

git switch <name> — switch to branch. Modern replacement for git checkout <branch>.

git switch -c <name> — create and switch. Equivalent to git checkout -b.

git branch -d <name> — delete branch (safe — won't delete unmerged). -D force delete.

git branch -m <old> <new> — rename branch.

git branch --merged — branches already merged into current. Safe to delete these.

Tracking & remote branches

Remote tracking branches: origin/main — local read-only reference to the remote branch state at last fetch.

git fetch — download remote changes without merging. Updates remote tracking branches.

git pull — fetch + merge (or rebase if configured). git pull --rebase — fetch + rebase.

git push -u origin <branch> — push and set upstream. After this, plain git push works.

git push origin --delete <branch> — delete remote branch.

git remote -v — list remotes. git remote add origin <url> — add remote.

Merge types

git merge <branch> — merge branch into current branch.

Fast-forward — if current branch has no new commits since the branch diverged, Git just moves the pointer forward. No merge commit. Clean linear history.

3-way merge — when both branches have diverged. Git finds the common ancestor and creates a merge commit with two parents.

git merge --no-ff <branch> — force a merge commit even if fast-forward is possible. Preserves branch history.

git merge --squash <branch> — squash all commits from branch into one staged change. Commit manually. Clean history but loses individual commits.

Conflict resolution

Conflicts happen when both branches changed the same lines. Git marks them in files:

<<<<<<< HEAD — your changes.

======= — separator.

>>>>>>> branch-name — incoming changes.

Resolve: edit the file to the correct final state, remove conflict markers, then git add <file> and git commit.

git merge --abort — abort in-progress merge and return to pre-merge state.

git mergetool — open configured visual merge tool.

Rebase basics

git rebase <branch> — move current branch commits on top of another branch. Rewrites commit history — new SHA hashes.

Merge vs rebase: merge preserves exact history with merge commits. Rebase creates a linear history as if you branched off later. Both are valid — teams should pick one strategy and stick to it.

Golden rule: never rebase commits that have been pushed to a shared remote branch. You'll rewrite history others are working on.

git rebase --abort — abort if conflicts arise.

git rebase --continue — after resolving conflict, continue rebase.

git rebase --skip — skip the conflicting commit.

Interactive rebase

git rebase -i HEAD~3 — interactively rebase last 3 commits. Opens editor with commit list.

Actions per commit:

pick — keep as-is.

reword — keep but edit message.

edit — pause to amend the commit.

squash — meld into previous commit, combine messages.

fixup — like squash but discard this commit's message.

drop — remove the commit entirely.

Use cases: clean up messy feature branch before merging, squash WIP commits, fix old commit messages, reorder commits.

Undo strategies

git restore <file> — discard unstaged changes in working directory. Permanent — cannot undo.

git restore --staged <file> — unstage a file (keep changes in working directory).

git revert <commit> — create a new commit that undoes the changes of a specific commit. Safe — doesn't rewrite history. Use on shared branches.

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 and discard all changes. Destructive.

reset rewrites history — only use on local commits not yet pushed.

Reflog — the safety net

git reflog — shows every position HEAD has been at, even after resets and rebases. Your undo history for the last 90 days.

Recover a lost commit: find it in reflog, then git checkout <sha> or git branch recover <sha>.

Recover after bad reset: git reflog → find SHA before reset → git reset --hard <sha>.

Almost nothing in Git is truly lost if you act before the garbage collector runs (default 90 days). Reflog is your escape hatch.

Stash

git stash — save dirty working directory and staging area. Stack-based.

git stash push -m 'description' — stash with a label.

git stash list — see all stashes.

git stash pop — apply most recent stash and remove it from stack.

git stash apply stash@{2} — apply specific stash without removing it.

git stash drop stash@{0} — delete a stash.

git stash branch <name> — create branch from stash. Useful when stash conflicts with current branch.

git stash --include-untracked — also stash untracked files.

Cherry-pick

git cherry-pick <commit> — apply a specific commit from another branch onto current branch. Creates a new commit with same changes but different SHA.

git cherry-pick A..B — apply range of commits (A exclusive, B inclusive).

git cherry-pick --no-commit <sha> — apply changes without committing. Review first.

Use cases: backport a bug fix to a release branch, pull a specific feature without merging the whole branch.

Tags

Tags mark specific points in history — typically release versions.

git tag v1.0.0 — lightweight tag (just a pointer, like a branch that doesn't move).

git tag -a v1.0.0 -m 'Release 1.0.0' — annotated tag. Has its own object with tagger, date, message. Prefer this for releases.

git tag — list tags. git show v1.0.0 — show tag details.

git push origin v1.0.0 — push a specific tag. git push origin --tags — push all tags. Tags are not pushed automatically.

git tag -d v1.0.0 — delete local tag. git push origin --delete v1.0.0 — delete remote tag.

Git Flow

Structured workflow with long-lived branches:

main — production code only. Tagged with releases.

develop — integration branch. All features merge here.

feature/* — branch from develop, merge back to develop.

release/* — branch from develop when ready to release. Only bug fixes. Merges to main + develop.

hotfix/* — branch from main for urgent fixes. Merges to main + develop.

Git Flow is heavy for small teams or continuous deployment. Better suited for versioned software with scheduled releases.

GitHub Flow

Simpler — good for continuous deployment:

1. Branch from main for any work.

2. Commit to your branch, push regularly.

3. Open a pull request when ready for review.

4. Get reviewed, iterate.

5. Merge to main → triggers deployment.

main is always deployable. No long-lived branches other than main. Simple, fast, works well for web apps with CI/CD.

Trunk-based development

Everyone commits to main (trunk) frequently — at least once a day. Short-lived feature branches (max 1-2 days) if any.

Relies on: feature flags to hide incomplete features, strong CI that catches regressions, small frequent commits.

Avoids: long-lived branches, big bang merges, merge conflicts. Used by Google, Facebook at scale.

Power commands

git bisect start — binary search through history to find which commit introduced a bug. git bisect good <sha> and git bisect bad to mark commits.

git grep 'pattern' — search across tracked files. Faster than regular grep in large repos.

git clean -fd — remove untracked files and directories. -n for dry run first.

git archive --format=zip HEAD > project.zip — export project without .git folder.

git submodule — embed another repo inside your repo. Complex — use with caution.

git worktree add ../hotfix hotfix-branch — check out another branch in a separate directory without cloning. Work on two branches simultaneously.

Common gotchas

Merge vs rebase — interviewers love this. Merge = preserves history + merge commit. Rebase = linear history, rewrites SHAs. Don't rebase shared branches.

git pull = git fetch + git merge. Many devs use git pull --rebase to keep history linear.

Detached HEAD — when you checkout a commit directly (not a branch). You're not on any branch. Create a branch to save work: git switch -c new-branch.

Force push git push --force — dangerous on shared branches. Use --force-with-lease instead — fails if someone else pushed since your last fetch.

.gitignore only ignores untracked files. If a file is already tracked, add it to .gitignore won't stop tracking it. Use git rm --cached <file> first.