Git
Core commands and concepts worth having at hand — not exhaustive, just the essentials.
The three states
Working directory → staging area (index) → repository (committed).
git status # what's changed / staged
git add <file> # working dir -> staging
git add -p # stage interactively, hunk by hunk
git commit -m "msg" # staging -> repo
git commit -am "msg" # stage all tracked changes + commit in one step
History & inspection
git log --oneline --graph --decorate
git log -p <file> # full diffs per commit for a file
git diff # working dir vs staging
git diff --staged # staging vs last commit
git blame <file> # who changed each line, and when
git show <commit> # full diff of one commit
Branching
git branch # list local branches
git switch -c feature/thing # create + switch (modern replacement for checkout -b)
git switch main # switch back
git branch -d feature/thing # delete (merged)
git branch -D feature/thing # delete (force, unmerged)
Merging & rebasing
git merge feature/thing # merge into current branch, creates a merge commit
git rebase main # replay current branch's commits on top of main
git rebase -i HEAD~3 # interactive: reword/squash/drop last 3 commits
- Merge preserves history exactly as it happened, including a merge commit.
- Rebase rewrites history to look linear — never rebase commits that are already pushed and shared, since it changes their SHAs.
- Interactive rebase actions:
pick,reword,edit,squash(s),fixup(f, like squash but discards the message),drop.
Undoing things
git restore <file> # discard uncommitted working-dir changes
git restore --staged <file> # unstage, keep working-dir 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 changes entirely
git revert <commit> # new commit that undoes an earlier one (safe for shared history)
Rule of thumb: reset rewrites history (fine locally, dangerous once pushed); revert adds new history (safe always).
Stashing
git stash # shelve working-dir + staged changes
git stash -u # also stash untracked files
git stash list
git stash pop # reapply + drop from stash list
git stash apply stash@{1} # reapply a specific stash, keep it in the list
Remotes
git remote -v
git fetch origin # download refs/objects, don't touch working dir
git pull # fetch + merge (or rebase, with --rebase / pull.rebase=true)
git push origin feature/thing
git push -u origin feature/thing # set upstream tracking on first push
Cherry-picking & tags
git cherry-pick <commit> # apply one specific commit onto the current branch
git tag v1.2.0
git tag -a v1.2.0 -m "release notes"
git push origin v1.2.0
git push origin --tags
Resolving conflicts
- Conflicting files show
<<<<<<<,=======,>>>>>>>markers. - Edit to the resolved content, remove the markers.
git add <file>to mark resolved.git commit(merge) orgit rebase --continue(rebase).- Bail out entirely with
git merge --abortorgit rebase --abort.
.gitignore basics
*.log
/tmp/
.env
!important.log # negate a pattern, un-ignore a specific file
Already-tracked files aren’t affected by .gitignore — untrack with git rm --cached <file> first.
Conventional commit format (if you’re using it)
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Common types: feat, fix, docs, style, refactor, perf, test, build, ci, chore. A ! after the type/scope (feat!:) or a BREAKING CHANGE: footer marks a breaking change.
Handy aliases
git config --global alias.co switch
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --decorate --all"