If you’ve ever typed git push and then stared at an error message wondering what you did wrong, this guide is for me just as much as it’s for you. I’ve spent years jumping between terminals, and no matter how experienced I get, I still keep a cheat sheet like this one pinned in a browser tab. Git is one of those tools that’s simple on the surface and endlessly deep once you start digging — rebasing, cherry-picking, reflogs, submodules. So I put together the reference I wish I’d had when I started: one place with the commands, the “why,” the gotchas, and the workflows that actually show up in real jobs.
This isn’t a dry man-page dump. It’s organized the way I actually use Git day to day — starting a project, making changes, collaborating with a team, and cleaning up the inevitable mess. Bookmark it, print it, or just keep it open in a split pane while you work.
Table of Contents
- Git vs GitHub: Quick Clarification
- Initial Setup and Configuration
- Creating and Cloning Repositories
- The Basic Workflow: Stage, Commit, Push
- Branching and Merging
- Working with Remotes
- Collaboration: Pull Requests, Forks, and Issues
- Undoing Things: Reset, Revert, and Checkout
- Rebasing and History Rewriting
- Stashing Changes
- Tags and Releases
- GitHub CLI (
gh) Commands - Submodules and Monorepos
- .gitignore and Housekeeping
- Security Best Practices
- Troubleshooting Common Errors
- Real-World Professional Workflows
- Common Mistakes to Avoid
- FAQs
- Interview Questions
- Printable Quick-Reference Summary
- Official Documentation Links
1. Git vs GitHub: Quick Clarification
Before diving in, I want to clear up something that trips up a lot of beginners. Git is the version control system — it runs locally on your machine and tracks changes to your files. GitHub is a cloud platform built around Git that adds collaboration features: pull requests, issue tracking, code review, project boards, and Actions for automation. You can use Git without ever touching GitHub, but GitHub without Git doesn’t exist. Everything below covers both the core Git commands and the GitHub-specific workflows layered on top.
2. Initial Setup and Configuration
The first thing I do on any new machine is set my identity, because every commit needs an author.
| Command | Purpose |
|---|---|
git config --global user.name "Your Name" | Sets your commit author name |
git config --global user.email "you@example.com" | Sets your commit author email |
git config --global core.editor "code --wait" | Sets VS Code as your default editor |
git config --global init.defaultBranch main | Sets default branch name to main |
git config --list | Shows all current config settings |
git config --global --edit | Opens the global config file directly |
Example:
git config --global user.name "Sarah Malik"
git config --global user.email "sarah@devmail.com"
Expected output: No output on success — Git configs are silent unless there’s an error.
I’d also recommend setting up SSH authentication early instead of typing your GitHub password (which doesn’t even work anymore for HTTPS pushes — you need a personal access token).
ssh-keygen -t ed25519 -C "your_email@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Then paste the public key (cat ~/.ssh/id_ed25519.pub) into GitHub under Settings → SSH and GPG Keys.
3. Creating and Cloning Repositories
| Command | Description |
|---|---|
git init | Initializes a new Git repository in the current folder |
git clone <url> | Clones a remote repository to your machine |
git clone <url> <folder-name> | Clones into a custom folder name |
git clone --depth 1 <url> | Shallow clone — only the latest commit, faster for CI |
git clone --branch <branch> <url> | Clones a specific branch only |
Example:
git clone git@github.com:sarah-dev/portfolio-site.git
Expected output:
Cloning into 'portfolio-site'...
remote: Enumerating objects: 120, done.
Receiving objects: 100% (120/120), done.
A quick real-world tip: if you’re cloning a huge repository just to peek at the latest code (not the full history), --depth 1 will save you a lot of time and bandwidth.
4. The Basic Workflow: Stage, Commit, Push
This is the loop you’ll run hundreds of times a week.
| Command | Description |
|---|---|
git status | Shows changed, staged, and untracked files |
git add <file> | Stages a specific file |
git add . | Stages all changes in the current directory |
git add -p | Interactively stages chunks of a file (great for clean commits) |
git commit -m "message" | Commits staged changes with a message |
git commit -am "message" | Stages and commits tracked file changes in one step |
git push | Pushes commits to the remote |
git push origin <branch> | Pushes a specific branch |
git pull | Fetches and merges remote changes into your current branch |
git log | Shows commit history |
git log --oneline --graph --all | Compact, visual commit history across branches |
Example workflow:
git status
git add src/app.js
git commit -m "Fix null pointer bug in user auth"
git push origin feature/auth-fix
Expected output after push:
Enumerating objects: 5, done.
To github.com:sarah-dev/portfolio-site.git
a1b2c3d..e4f5g6h feature/auth-fix -> feature/auth-fix
One habit I picked up early: write commit messages in the imperative mood — “Fix bug,” not “Fixed bug” or “Fixes bug.” It matches how Git itself talks about commits (“This commit will fix…”) and it’s the convention most teams expect in code review.
5. Branching and Merging
Branches are where Git actually earns its reputation as a collaboration tool.
| Command | Description |
|---|---|
git branch | Lists local branches |
git branch -a | Lists local and remote branches |
git branch <name> | Creates a new branch |
git checkout <branch> | Switches to a branch |
git checkout -b <name> | Creates and switches to a new branch |
git switch <branch> | Modern alternative to checkout for switching |
git switch -c <name> | Modern alternative for creating + switching |
git branch -d <name> | Deletes a local branch (safe — only if merged) |
git branch -D <name> | Force-deletes a local branch |
git merge <branch> | Merges the named branch into your current branch |
git merge --no-ff <branch> | Forces a merge commit even if fast-forward is possible |
Example:
git checkout -b feature/dark-mode
# ...make changes...
git add .
git commit -m "Add dark mode toggle to settings page"
git checkout main
git merge feature/dark-mode
Expected output on a clean merge:
Updating a1b2c3d..e4f5g6h
Fast-forward
src/settings.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
If you hit a merge conflict, Git will mark the conflicting sections in the file with <<<<<<<, =======, and >>>>>>> markers. You resolve them manually, then run:
git add <resolved-file>
git commit
Branching best practice I follow: name branches by type and purpose — feature/, bugfix/, hotfix/, chore/ — so anyone scanning the branch list instantly understands intent.
6. Working with Remotes
| Command | Description |
|---|---|
git remote -v | Lists remotes and their URLs |
git remote add origin <url> | Adds a new remote named “origin” |
git remote rename <old> <new> | Renames a remote |
git remote remove <name> | Removes a remote |
git fetch | Downloads remote changes without merging |
git fetch --all | Fetches from all remotes |
git push -u origin <branch> | Pushes and sets upstream tracking |
git remote set-url origin <url> | Changes the URL of an existing remote |
Example:
git remote add origin git@github.com:sarah-dev/portfolio-site.git
git push -u origin main
Once upstream is set, plain git push and git pull work without specifying the branch each time.
7. Collaboration: Pull Requests, Forks, and Issues
This is where GitHub itself (not just Git) comes into play.
Forking workflow (common on open source projects):
- Fork the repo on GitHub (via the web UI).
- Clone your fork:
git clone git@github.com:yourname/repo.git - Add the original repo as an upstream remote:
git remote add upstream git@github.com:original-owner/repo.git - Sync regularly:
git fetch upstreamthengit merge upstream/main - Push changes to your fork and open a pull request from the GitHub web UI.
Pull request best practices I follow:
- Keep PRs small and focused on one change — reviewers move faster on a 100-line diff than a 1,000-line one.
- Write a clear description: what changed, why, and how to test it.
- Link related issues using
Closes #12orFixes #45in the PR description — GitHub auto-closes the issue on merge. - Request review from specific teammates rather than leaving it open-ended.
- Respond to review comments with commits, not force-pushes, until the PR is close to merging (it keeps the review history readable).
Issues: Use labels (bug, enhancement, good first issue), assignees, and milestones to keep a repo organized. Referencing a commit with an issue number (git commit -m "Fix #23: correct date formatting") automatically links them.
8. Undoing Things: Reset, Revert, and Checkout
Mistakes happen constantly, and Git gives you several ways to undo them — each with a different blast radius.
| Command | Description | Danger Level |
|---|---|---|
git checkout -- <file> | Discards uncommitted changes to a file | Medium |
git restore <file> | Modern alternative to checkout for discarding changes | Medium |
git reset <file> | Unstages a file, keeps changes | Low |
git reset --soft HEAD~1 | Undoes last commit, keeps changes staged | Low |
git reset --mixed HEAD~1 | Undoes last commit, keeps changes unstaged (default) | Medium |
git reset --hard HEAD~1 | Undoes last commit and deletes all changes | High — irreversible without reflog |
git revert <commit> | Creates a new commit that undoes a previous one | Low — safe for shared branches |
Example — safely undoing a pushed commit:
git revert e4f5g6h
Expected output:
[main 9k8j7h6] Revert "Add dark mode toggle to settings page"
1 file changed, 12 deletions(-)
The rule I follow: use reset only on commits that haven’t been pushed yet, and use revert for anything already shared with teammates. Rewriting shared history with reset --hard and a force push is one of the fastest ways to make enemies on a team.
If you do mess up badly, git reflog is your safety net — it records every place HEAD has pointed, even after a hard reset, and lets you recover “lost” commits.
9. Rebasing and History Rewriting
| Command | Description |
|---|---|
git rebase <branch> | Replays your commits on top of another branch |
git rebase -i HEAD~5 | Interactive rebase — squash, reword, reorder, or drop the last 5 commits |
git rebase --continue | Continues a rebase after resolving conflicts |
git rebase --abort | Cancels a rebase and returns to the original state |
git cherry-pick <commit> | Applies a specific commit from another branch onto the current one |
git commit --amend | Edits the most recent commit (message or content) |
Example — cleaning up messy commits before opening a PR:
git rebase -i HEAD~4
This opens an editor listing your last 4 commits with pick next to each. Changing pick to squash (or s) combines commits, and reword lets you edit messages.
Golden rule of rebasing: never rebase a branch that other people are already working from. Rebase your own feature branches freely; leave shared branches like main alone.
10. Stashing Changes
Useful when you need to switch context quickly without committing half-finished work.
| Command | Description |
|---|---|
git stash | Stashes current changes |
git stash save "message" | Stashes with a descriptive label |
git stash list | Lists all stashes |
git stash pop | Reapplies the most recent stash and removes it from the list |
git stash apply | Reapplies a stash but keeps it in the list |
git stash drop | Deletes a specific stash |
git stash clear | Deletes all stashes |
Example:
git stash save "WIP: refactoring payment form"
git checkout main
git pull
git checkout feature/payment-form
git stash pop
11. Tags and Releases
| Command | Description |
|---|---|
git tag | Lists all tags |
git tag v1.0.0 | Creates a lightweight tag |
git tag -a v1.0.0 -m "First stable release" | Creates an annotated tag with a message |
git push origin v1.0.0 | Pushes a specific tag |
git push origin --tags | Pushes all tags |
git tag -d v1.0.0 | Deletes a local tag |
git push origin --delete v1.0.0 | Deletes a remote tag |
On GitHub specifically, I usually pair a tag with a formal Release (via the web UI or gh release create), attaching changelogs and binaries so users don’t have to dig through commit history to find what’s new.
12. GitHub CLI (gh) Commands
The GitHub CLI lets me manage issues, PRs, and repos without leaving the terminal.
| Command | Description |
|---|---|
gh repo create | Creates a new GitHub repository |
gh repo clone <repo> | Clones a repository |
gh pr create | Opens a pull request from the current branch |
gh pr list | Lists open pull requests |
gh pr checkout <number> | Checks out a PR locally for review |
gh pr merge <number> | Merges a pull request |
gh issue create | Creates a new issue |
gh issue list | Lists issues |
gh workflow run <name> | Manually triggers a GitHub Actions workflow |
gh auth login | Authenticates the CLI with your GitHub account |
Example:
gh pr create --title "Add dark mode" --body "Implements toggle in settings" --base main
13. Submodules and Monorepos
| Command | Description |
|---|---|
git submodule add <url> <path> | Adds another repo as a submodule |
git submodule update --init --recursive | Initializes and pulls submodule content |
git submodule foreach git pull | Updates all submodules to latest |
Submodules are powerful but notoriously fiddly — a lot of teams now prefer monorepo tooling (like Nx or Turborepo) over submodules unless there’s a strong reason to keep repos physically separate.
14. .gitignore and Housekeeping
A .gitignore file tells Git which files to never track — node_modules, build artifacts, .env files, IDE settings.
Example .gitignore for a Node.js project:
node_modules/
.env
dist/
.DS_Store
*.log
| Command | Description |
|---|---|
git rm --cached <file> | Untracks a file without deleting it locally |
git clean -n | Previews untracked files that would be removed |
git clean -fd | Removes untracked files and directories |
git gc | Cleans up and optimizes the local repository |
15. Security Best Practices
- Never commit secrets. Use
.gitignorefor.envfiles and secret configs from day one — once a secret is in history, rotating the credential is often easier than fully scrubbing it out. - Use personal access tokens or SSH keys, not passwords, for authentication.
- Enable two-factor authentication on your GitHub account — it’s required for many organizations now anyway.
- Sign your commits with GPG (
git commit -S -m "message") if you need verified authorship, especially for open source contributions. - If a secret does leak, rotate the credential immediately, then use tools like
git filter-repoor BFG Repo-Cleaner to scrub history — a simple revert commit does not remove it from history. - Review dependabot and security alerts on GitHub regularly; don’t let them pile up unread.
- Protect your main branch with branch protection rules — require PR reviews and passing status checks before merge.
16. Troubleshooting Common Errors
| Error | Likely Cause | Fix |
|---|---|---|
fatal: not a git repository | You’re not inside a Git-tracked folder | Run git init or cd into the right folder |
Updates were rejected because the remote contains work that you do not have | Remote has commits you don’t | Run git pull --rebase then push again |
Permission denied (publickey) | SSH key not set up or not added to GitHub | Check ssh -T git@github.com and re-add your key |
merge conflict markers in files | Two branches changed the same lines | Manually resolve, then git add and git commit |
detached HEAD state | You checked out a commit instead of a branch | git checkout -b new-branch-name to save your work |
fatal: refusing to merge unrelated histories | Merging two repos with no shared commit history | Add --allow-unrelated-histories to the merge command |
| Large file rejected on push | File exceeds GitHub’s size limit | Use Git LFS (git lfs track "*.psd") |
17. Real-World Professional Workflows
Trunk-based development: Small teams shipping continuously often keep one long-lived branch (main) and use short-lived feature branches merged in within a day or two, guarded by CI and feature flags rather than long integration branches.
Git Flow: Larger, release-driven teams sometimes still use develop, release/*, and hotfix/* branches alongside main, giving more structure at the cost of more overhead.
Code review loop I use daily:
git checkout -b feature/export-csv
# work, commit
git push -u origin feature/export-csv
gh pr create
# address review comments with new commits
git push
# once approved
gh pr merge --squash
Hotfix workflow:
git checkout main
git checkout -b hotfix/critical-login-bug
# fix, commit
git push -u origin hotfix/critical-login-bug
gh pr create --base main
gh pr merge --squash
git tag -a v1.2.1 -m "Hotfix: login bug"
git push origin v1.2.1
18. Common Mistakes to Avoid
- Committing directly to
maininstead of working in a feature branch. - Writing vague commit messages like “fix stuff” or “update.”
- Force-pushing to a shared branch without warning teammates.
- Committing large binaries or
node_modulesbecause.gitignorewasn’t set up first. - Resolving merge conflicts by blindly accepting “theirs” or “ours” without reading the actual code.
- Forgetting to
git pullbefore starting new work, leading to painful divergent histories. - Leaving pull requests open for weeks, causing painful merge conflicts later.
- Storing credentials or API keys directly in code instead of environment variables.
19. FAQs
Q: What’s the difference between git fetch and git pull? git fetch downloads remote changes but doesn’t touch your working directory. git pull is essentially fetch + merge (or rebase, depending on config) in one step.
Q: Can I undo a git push? Not by deleting history cleanly if others may have already pulled it. The safe approach is git revert, which adds a new commit undoing the change rather than rewriting shared history.
Q: What’s the difference between merge and rebase? Merge preserves the exact history of both branches and creates a merge commit. Rebase rewrites your branch’s commits to sit on top of another branch’s latest commit, producing a linear history — but it should only be done on branches not shared with others.
Q: How do I recover a deleted branch? If it was deleted locally, git reflog will usually show the last commit on that branch, and you can recreate it with git checkout -b branch-name <commit-hash>.
Q: What is a detached HEAD, and is it bad? It just means you’ve checked out a specific commit rather than a branch. It’s not dangerous, but any commits you make there can be lost once you switch away unless you create a branch from that point first.
Q: Do I need GitHub to use Git? No — Git works entirely locally or with any Git-compatible remote (GitLab, Bitbucket, self-hosted servers). GitHub is just the most popular hosting platform built around it.
Q: What’s the difference between a fork and a branch? A branch lives inside the same repository. A fork is a full copy of the entire repository under your own account, typically used when you don’t have write access to the original.
20. Interview Questions
- Explain the difference between
git mergeandgit rebase, and when you’d use each. - How would you recover work after an accidental
git reset --hard? - Walk through how you’d resolve a merge conflict in a shared file.
- What’s the purpose of a
.gitignorefile, and how do you remove a file that’s already tracked? - Describe your typical branching strategy on a team project.
- What happens internally when you run
git commit? - How do you squash multiple commits into one before opening a pull request?
- What’s the difference between
git reset --soft,--mixed, and--hard? - How would you handle a leaked API key that was accidentally committed?
- What’s the difference between
originandupstreamin a fork-based workflow?
21. Printable Quick-Reference Summary
SETUP
git config --global user.name "Name"
git config --global user.email "email"
START
git init
git clone <url>
DAILY WORKFLOW
git status
git add .
git commit -m "message"
git push
git pull
BRANCHING
git checkout -b <branch>
git switch <branch>
git merge <branch>
git branch -d <branch>
UNDO
git restore <file>
git reset --soft HEAD~1
git revert <commit>
git reflog
REBASE / CLEANUP
git rebase -i HEAD~n
git commit --amend
git cherry-pick <commit>
STASH
git stash
git stash pop
REMOTES
git remote -v
git fetch
git push -u origin <branch>
TAGS
git tag -a v1.0.0 -m "message"
git push origin --tags
GITHUB CLI
gh pr create
gh pr merge
gh issue create
22. Official Documentation Links
- Git official documentation: https://git-scm.com/doc
- GitHub Docs: https://docs.github.com
- GitHub CLI manual: https://cli.github.com/manual
- Git Pro Book (free online): https://git-scm.com/book/en/v2
- GitHub Skills (interactive courses): https://skills.github.com
That’s the whole toolkit I actually reach for, whether I’m shipping a solo side project or working through a pull request queue with a team of ten. Keep this open next to your terminal, and over time you won’t even need it — the commands become muscle memory. Until then, bookmark it.