| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github/workflows | ||
| .gitignore | ||
| CONTRIBUTING.md | ||
| LICENSE | ||
| README.md | ||
Git & GitHub Handbook
A practical guide to using Git and GitHub in real projects. Learn the concepts, commands, workflows, and recovery techniques developers use every day.
Target audience: This guide is for people who are new to Git but want to understand real-world team workflows. It also works as a reference for junior developers, open-source contributors, and experienced users who want safer habits and sharper troubleshooting.
Last updated: 2026-05-26
Quick Start
If you only need the daily workflow, start here. The deeper explanations come after this section.
git status
git pull
git switch -c feature/name
git add .
git commit -m "Add feature"
git push -u origin feature/name
Then open a pull request on GitHub.
Important
A commit is local until you push it. GitHub cannot see your work, and you usually cannot open a pull request, until your branch exists on GitHub.
60-Second Mental Model
| Step | Purpose | Command |
|---|---|---|
| Check state | See your branch and changed files | git status |
| Review changes | Inspect the actual line-by-line edits | git diff |
| Stage changes | Choose what belongs in the next commit | git add |
| Save changes | Create a local snapshot | git commit |
| Upload branch | Send commits to GitHub | git push |
| Open review | Discuss and approve changes | Pull Request |
flowchart LR
A["Working directory<br/>edit files"] --> B["Staging area<br/>git add"]
B --> C["Local repository<br/>git commit"]
C --> D["Remote repository<br/>git push"]
Tip
The diagram above is the core Git loop. Most commands either inspect one of these areas or move changes from one area to the next.
Remember This First
These commands solve most day-to-day situations:
| Command | Why It Matters |
|---|---|
git status |
Shows what Git sees right now |
git diff |
Shows exactly what changed |
git add |
Stages changes for the next commit |
git commit |
Saves staged changes locally |
git push |
Uploads commits to a remote |
git pull |
Downloads and integrates remote changes |
git switch -c |
Creates and switches to a new branch |
git restore |
Restores working-tree or staged changes |
git revert |
Safely undoes a committed change with a new commit |
git log --oneline |
Shows commit history compactly |
Key Terms Before You Continue
| Term | Short Meaning |
|---|---|
| Commit | A saved snapshot of project changes |
| Branch | A separate line of work |
| Remote | Another copy of the repository, usually on GitHub |
origin |
The default name for the remote you cloned from |
upstream |
Often the original repository when you work from a fork |
HEAD |
Pointer to the branch or commit you are currently looking at |
| Staging area | Changes prepared for the next commit |
| Merge | Combine branch histories |
| Rebase | Replay commits on top of another base commit |
| Pull request | GitHub review process for proposed changes |
| Clone | Download a repository and its history |
| Fork | Your GitHub copy of someone else's repository |
| Tag | A named pointer to a specific commit, often a release |
| Stash | Temporary storage for unfinished work |
| Reflog | Local safety log that helps recover lost commits |
See the full Glossary for more detail.
Table Of Contents
- Quick Start
- Why This Guide Exists
- Git And GitHub In Plain English
- Core Concepts
- Decision Tables
- Installation Guide
- First-Time Git Configuration
- SSH Setup For GitHub
- Create Your First Repository
- Clone An Existing Repository
- The Everyday Commit Workflow
- Branches Explained
- Stashing Unfinished Work
- Working With Remote Repositories
- GitHub CLI
- Pull Requests
- GitHub Team Workflows
- Merging, Squashing, And Rebasing
- Undoing Changes Safely
- Resolving Merge Conflicts
- GitHub Issues
- Forking Repositories
- Open Source Contribution Workflow
- Tags, Releases, And Semantic Versioning
- Professional Workflow Examples
- Practical Mini Project
- Best Practices
- Security
- Common Mistakes
- Troubleshooting
- How To Read Common Git Errors
- Cheat Sheets
- Advanced Tips For Power Users
- FAQ
- Glossary
- Further Reading
- What To Do Next
- Final One-Page Cheat Sheet
Why This Guide Exists
Git is one of the most important tools in modern software development, but it can feel confusing at first because it mixes several ideas at once: saving work, comparing versions, collaborating with others, reviewing code, publishing releases, and recovering from mistakes.
This guide is designed to be a practical handbook you can return to whenever you need to:
- Save your work safely.
- Understand what Git is doing.
- Collaborate with teammates on GitHub.
- Fix common mistakes without panic.
- Contribute to open source projects professionally.
- Build reliable habits used by experienced developers.
Tip
If you are lost, start with
git status. It is the safest and most useful Git command because it tells you what branch you are on, what changed, and what Git expects next.
Git And GitHub In Plain English
What Is Git?
Git is a distributed version control system. In simple terms, Git tracks changes to files over time so you can:
- Save meaningful versions of a project.
- Compare what changed between versions.
- Return to earlier versions when needed.
- Work on multiple ideas at the same time using branches.
- Collaborate without constantly overwriting each other.
Git runs on your computer. You can use Git without GitHub.
What Is GitHub?
GitHub is a cloud platform built around Git repositories. It adds collaboration features such as:
- Remote repository hosting.
- Pull requests.
- Code review.
- Issues and project planning.
- Actions for automation and CI/CD.
- Releases.
- Wikis and documentation.
- Open source discovery.
Git is the version control tool. GitHub is a collaboration platform that hosts Git repositories.
Why Developers Use Them
| Need | How Git Helps | How GitHub Helps |
|---|---|---|
| Save work | Commits store snapshots | Remote backups store commits online |
| Work safely | Branches isolate changes | Pull requests review changes before merge |
| Collaborate | Merges combine work | Reviews, comments, checks, and permissions |
| Fix mistakes | Revert, restore, reset, reflog | PR history and protected branches |
| Release software | Tags mark versions | Releases publish changelogs and assets |
| Track tasks | Commit messages reference context | Issues organize bugs, ideas, and work |
Note
GitHub is not the only Git hosting service. GitLab, Bitbucket, Azure DevOps, and self-hosted Git servers use the same Git foundations.
Core Concepts
Before memorizing commands, learn the pieces Git works with.
Repository
A repository, often called a repo, is a project folder tracked by Git. It contains your files plus a hidden .git directory where Git stores history.
git init
Commit
A commit is a saved snapshot of your project at a specific moment.
Each commit has:
- A unique hash, such as
a1b2c3d. - An author.
- A timestamp.
- A commit message.
- A reference to the previous commit.
Working Directory, Staging Area, Local Repository, And Remote Repository
Git becomes much easier when you understand the four places your work can live:
| Area | Plain-English Meaning | Typical Command |
|---|---|---|
| Working directory | Files currently being edited on your machine | git status, git diff |
| Staging area | Changes prepared for the next commit | git add, git restore --staged |
| Local repository | Saved commit history on your machine | git commit, git log |
| Remote repository | Copy hosted on GitHub or another server | git push, git fetch, git pull |
Working directory -> Staging area -> Local repository -> Remote repository
edit files git add git commit git push
flowchart LR
WD["Working directory<br/>Files you edit"] -->|git add| ST["Staging area<br/>Next commit"]
ST -->|git commit| LR["Local repository<br/>History on your machine"]
LR -->|git push| RR["Remote repository<br/>GitHub / server"]
RR -->|git fetch / git pull| LR
Tip
Think of staging as packing a box. You can decide exactly which changes go into the next commit before sealing the box with
git commit.
Local History Vs Remote History
Git history exists locally before it exists on GitHub.
| Idea | Meaning |
|---|---|
| Local commit | Saved on your machine only |
| Pushed commit | Uploaded to a remote such as GitHub |
git fetch |
Downloads remote history without changing your working files |
git pull |
Downloads remote history and integrates it into your current branch |
| Pull request | Can usually be opened only after your branch has been pushed |
Important
Your laptop and GitHub can disagree for a while. That is normal.
git pushuploads your local commits.git fetchdownloads remote information.git pulldownloads and integrates remote information.
Branch
A branch is a movable pointer to a line of work. Branches let you build a feature, fix a bug, or experiment without changing the main version immediately.
git switch -c feature/login-form
Remote
A remote is a named connection to another copy of the repository, usually on GitHub.
git remote -v
The default remote is usually called origin.
HEAD
HEAD points to the branch or commit you are currently looking at. A simple analogy: HEAD is like the playback needle pointing to the commit currently being played.
Usually HEAD points to a branch:
main -> commit C
HEAD -> main
In a detached HEAD state, HEAD points directly to a commit instead of a branch:
commit A -> commit B -> commit C
^
HEAD
Detached HEAD is useful for inspecting old history, but if you make new work there, save it on a branch:
git switch -c recovery/my-work
Pull Request
A pull request, often called a PR, is a GitHub discussion around proposed changes. It lets people review code before those changes are merged.
Note
Pull requests are a GitHub feature, not a core Git command. Git handles commits and branches; GitHub adds review, comments, checks, and merge buttons.
Decision Tables
Use these tables when you know what you want but are unsure which Git tool fits the situation.
Should I Use Merge, Rebase, Or Squash?
| Use This | When | What It Does | Watch Out For |
|---|---|---|---|
| Merge | You want to preserve branch history | Combines branches with a merge commit when needed | History can look busier |
| Rebase | You want a linear local feature branch | Replays your commits on top of another branch | Rewrites commits; avoid on shared branches unless expected |
| Squash | A branch has many noisy commits | Combines many commits into one clean commit | Loses individual commit detail |
Important
Avoid rebasing shared branches unless your team explicitly expects it. Rebase is best for local or personal feature branches.
Should I Use Reset, Restore, Or Revert?
| Use This | Best For | Changes Files? | Changes Local History? | Changes Remote History? |
|---|---|---|---|---|
git restore |
Working-tree or staging-area changes | Yes | No | No |
git reset --soft |
Undoing local unpushed commits while keeping changes staged | No | Yes | No |
git reset --hard |
Discarding local commits and file changes | Yes | Yes | No, unless pushed later |
git revert |
Undoing commits that were already pushed | Yes | Adds new commit | No rewrite |
Caution
git reset --hardcan delete local work. Usegit revertfor pushed commits andgit restorefor ordinary file or staging changes.
Should I Use HTTPS Or SSH?
| Option | Good For | Pros | Cons |
|---|---|---|---|
| HTTPS | Beginners, locked-down networks, quick cloning | Works almost everywhere, simple URLs, integrates with credential managers | May require token or credential-manager setup for pushing |
| SSH | Frequent contributors and daily development | Convenient after setup, no token prompt for each push, strong key-based auth | Initial key setup can be confusing; some networks block SSH |
Both HTTPS and SSH are valid. HTTPS is not obsolete. SSH is often more comfortable once you contribute regularly.
Should I Create A Branch, Fork, Or Clone?
| Action | Use When | Example |
|---|---|---|
| Clone | You need a local copy of a repository | git clone URL |
| Branch | You have write access and want isolated work | git switch -c feature/name |
| Fork | You do not have write access or want your own GitHub copy | Fork on GitHub, then clone your fork |
Should I Use git branch -d Or git branch -D?
| Command | Behavior | Recommendation |
|---|---|---|
git branch -d branch-name |
Deletes only if Git believes the branch was merged | Use by default |
git branch -D branch-name |
Force-deletes even with unmerged work | Use only when you are sure |
Installation Guide
Install Git once on your machine, then verify it from the terminal.
Check Whether Git Is Already Installed
git --version
If Git is installed, you will see something like:
git version 2.45.0
Windows installation
Recommended options:
| Method | Command Or Link | Notes |
|---|---|---|
| Official installer | git-scm.com/download/win | Best default for most users |
| Windows Package Manager | winget install --id Git.Git -e --source winget |
Convenient for terminal users |
| Chocolatey | choco install git |
Good if you already use Chocolatey |
After installation, open a new terminal and run:
git --version
Tip
On Windows, Git for Windows includes Git Bash and Git Credential Manager. Git Bash gives you a Unix-like shell, while Credential Manager helps GitHub authentication work smoothly.
macOS installation
Recommended options:
| Method | Command Or Link | Notes |
|---|---|---|
| Xcode Command Line Tools | xcode-select --install |
Simple and common |
| Homebrew | brew install git |
Great for developers using Homebrew |
| Official installer | git-scm.com/download/mac | Manual installer |
Verify:
git --version
Linux installation
Use your distribution package manager.
# Debian / Ubuntu
sudo apt update
sudo apt install git
# Fedora
sudo dnf install git
# Arch Linux
sudo pacman -S git
Verify:
git --version
Important
After installing Git, configure your name and email before making commits. This information becomes part of your commit history.
First-Time Git Configuration
Git stores configuration at several levels:
| Level | Scope | Example |
|---|---|---|
| System | All users on the computer | Rarely needed |
| Global | Your user account | Most common |
| Local | One repository | Project-specific settings |
Set Your Name And Email
Use the same email address that is connected to your GitHub account.
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
Check your configuration:
git config --global --list
Set The Default Branch Name
Most modern projects use main as the default branch.
git config --global init.defaultBranch main
Choose A Default Editor
Examples:
# Visual Studio Code
git config --global core.editor "code --wait"
# Vim
git config --global core.editor "vim"
# Nano
git config --global core.editor "nano"
Recommended Quality-Of-Life Settings
# Show colors in Git output
git config --global color.ui auto
# Reuse recorded conflict resolutions when possible
git config --global rerere.enabled true
# Make pulls safer by requiring an explicit strategy when histories diverge
git config --global pull.ff only
Warning
pull.ff onlyis a clean, strict default, but it meansgit pullmay stop if your branch and the remote branch both have new commits. When that happens, choose whether to merge or rebase intentionally.
Line Ending Settings
Line endings can differ between Windows and Unix-like systems.
# Windows
git config --global core.autocrlf true
# macOS / Linux
git config --global core.autocrlf input
Tip
Teams can avoid line-ending noise by adding a
.gitattributesfile to the repository.
Example:
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
SSH Setup For GitHub
GitHub supports HTTPS and SSH. HTTPS is simple. SSH is convenient for frequent contributors because you can authenticate with a key instead of typing credentials.
SSH Setup Overview
| Step | Purpose |
|---|---|
| Generate an SSH key | Creates a private/public key pair |
| Add key to SSH agent | Makes the key available to Git |
| Add public key to GitHub | Allows GitHub to recognize your machine |
| Test connection | Confirms everything works |
Caution
Never share your private key. Your private key usually lives in
~/.ssh/id_ed25519. The public key ends with.puband is safe to add to GitHub.
Check For Existing SSH Keys
ls ~/.ssh
Look for files such as:
id_ed25519
id_ed25519.pub
Generate A New SSH Key
ssh-keygen -t ed25519 -C "you@example.com"
Press Enter to accept the default file location. Use a passphrase if you want stronger local protection.
Start The SSH Agent And Add Your Key
macOS or Linux
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
Windows PowerShell
Get-Service ssh-agent | Set-Service -StartupType Automatic
Start-Service ssh-agent
ssh-add $env:USERPROFILE\.ssh\id_ed25519
Copy The Public Key
macOS clipboard
pbcopy < ~/.ssh/id_ed25519.pub
Windows PowerShell clipboard
Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub | Set-Clipboard
Linux clipboard
xclip -selection clipboard < ~/.ssh/id_ed25519.pub
If xclip is not installed, print the key and copy it manually:
cat ~/.ssh/id_ed25519.pub
Add The Key To GitHub
- Open GitHub.
- Go to Settings.
- Open SSH and GPG keys.
- Click New SSH key.
- Paste your public key.
- Save.
Test The Connection
ssh -T git@github.com
Expected result:
Hi username! You've successfully authenticated, but GitHub does not provide shell access.
Note
That message is good news. It means authentication worked. GitHub is only saying SSH is for Git operations, not for opening a remote shell.
Create Your First Repository
You can create a repository on GitHub first, or create a local project first and connect it later.
Option A: Create A Repository On GitHub
- Click New repository on GitHub.
- Choose an owner and repository name.
- Add a short description.
- Choose public or private visibility.
- Optionally add:
README.md.gitignore- License
- Click Create repository.
Tip
Add a
.gitignorewhen creating a project with generated files, dependencies, build outputs, or secrets. It keeps your repository clean from the beginning.
Option B: Create A Local Repository
mkdir my-project
cd my-project
git init
Create a README:
echo "# My Project" > README.md
Make your first commit:
git add README.md
git commit -m "Add project README"
Connect to GitHub:
git remote add origin git@github.com:your-username/my-project.git
git push -u origin main
Recommended Starter Files
| File | Why It Matters |
|---|---|
README.md |
Explains what the project is and how to use it |
.gitignore |
Prevents unwanted files from being committed |
LICENSE |
Defines how others can use the project |
CONTRIBUTING.md |
Explains how to contribute |
CODE_OF_CONDUCT.md |
Sets community expectations |
.github/PULL_REQUEST_TEMPLATE.md |
Helps contributors open better PRs |
.github/ISSUE_TEMPLATE/ |
Makes bug reports and feature requests clearer |
Clone An Existing Repository
Cloning downloads a full copy of a repository, including its commit history.
Clone With SSH
git clone git@github.com:octocat/Hello-World.git
cd Hello-World
Clone With HTTPS
git clone https://github.com/octocat/Hello-World.git
cd Hello-World
Clone Into A Custom Folder
git clone git@github.com:octocat/Hello-World.git hello-world-demo
cd hello-world-demo
What Happens After Cloning?
Git automatically creates:
| Item | Meaning |
|---|---|
| Local repository | The copy on your machine |
origin remote |
The GitHub repository you cloned from |
| Default branch | Usually main |
| Working tree | The checked-out project files |
Check everything:
git status
git remote -v
git branch
The Everyday Commit Workflow
Most Git work follows this loop:
Edit files -> Review changes -> Stage changes -> Commit -> Push -> Open PR
1. Check Status
git status
Use this before and after most Git commands.
2. Review What Changed
git diff
Review staged changes:
git diff --staged
Important
Review your diff before committing. This catches debug code, accidental secrets, unrelated edits, and formatting noise.
3. Stage Files
Stage all changes:
git add .
Stage one file:
git add src/app.js
Stage part of a file interactively:
git add -p
Tip
Use
git add -pwhen one file contains multiple unrelated changes. It helps you create smaller, cleaner commits.
4. Commit
git commit -m "Add user profile page"
Good commit messages are short, specific, and written in the imperative mood.
| Weak Message | Better Message |
|---|---|
fix stuff |
Fix login redirect after session timeout |
update |
Update checkout validation messages |
changes |
Add empty state for project dashboard |
bug |
Prevent duplicate invoice creation |
5. Push
git push
For a new branch:
git push -u origin feature/user-profile
The -u flag sets an upstream branch so future pushes can use plain git push.
6. Open A Pull Request
After pushing a branch, GitHub usually shows a button to open a PR.
Include:
- What changed.
- Why it changed.
- Screenshots for UI changes.
- Testing notes.
- Links to related issues.
Branches Explained
Branches let you work independently without disturbing the stable version of the project.
Common Branch Names
| Branch | Purpose |
|---|---|
main |
Stable production-ready code |
develop |
Integration branch used by some teams |
feature/login |
New feature work |
fix/navbar-overlap |
Bug fix |
hotfix/payment-error |
Urgent production fix |
docs/git-guide |
Documentation change |
chore/update-deps |
Maintenance task |
Create And Switch To A Branch
git switch -c feature/search
Older command:
git checkout -b feature/search
Switch Branches
git switch main
git switch feature/search
List Branches
git branch
git branch -a
Rename A Branch
git branch -m old-name new-name
If the branch was already pushed:
git push origin --delete old-name
git push -u origin new-name
Delete A Branch
Delete a local branch:
git branch -d feature/search
Force-delete a local branch:
git branch -D feature/search
Delete a remote branch:
git push origin --delete feature/search
Warning
Use
git branch -Donly when you are sure you no longer need the branch. It deletes even if Git thinks the branch contains unmerged work.
Branch Workflow Checklist
- Start from the latest
main. - Create a focused branch.
- Commit small, related changes.
- Push the branch.
- Open a pull request.
- Update the branch if review or CI requires changes.
- Merge after approval.
- Delete the branch after merge.
Stashing Unfinished Work
Stash is temporary storage for changes you are not ready to commit. It is useful when you need to switch branches, pull updates, or quickly inspect another task without losing your current edits.
git stash
Stash with a message:
git stash push -m "WIP: dashboard filters"
List stashes:
git stash list
Apply and remove the latest stash:
git stash pop
Apply but keep the stash saved:
git stash apply
Drop the latest stash:
git stash drop
Note
Stash is temporary storage, not a replacement for commits. If the work matters, create a branch and commit it.
Working With Remote Repositories
A remote repository is another copy of your project, usually hosted on GitHub.
View Remotes
git remote -v
Typical output:
origin git@github.com:your-name/project.git (fetch)
origin git@github.com:your-name/project.git (push)
Add A Remote
git remote add origin git@github.com:your-name/project.git
Change A Remote URL
git remote set-url origin git@github.com:your-name/new-project.git
Fetch Without Merging
git fetch origin
fetch downloads remote updates but does not change your working files.
Pull Remote Changes
git pull
pull means:
git fetch + integrate changes
Depending on configuration, integration may be a merge, rebase, or fast-forward.
Push Local Commits
git push
Push a new branch:
git push -u origin feature/search
Note
originis just a name. It is a convention, not a magic keyword. You can have multiple remotes, such asoriginfor your fork andupstreamfor the original project.
GitHub CLI
The GitHub CLI, gh, lets you perform common GitHub actions from the terminal. It is optional, but useful when you create repositories, open pull requests, review PRs, or publish releases frequently.
Check whether it is installed:
gh --version
Authenticate:
gh auth login
Common gh Commands
| Goal | Command |
|---|---|
| Create a repository | gh repo create my-project --public --clone |
| Create a pull request | gh pr create --fill |
| Create a PR with title and body | gh pr create --title "Add search" --body "Adds product search." |
| Check out a PR locally | gh pr checkout 42 |
| View PR status | gh pr status |
| Create a release | gh release create v1.0.0 --generate-notes |
Web UI And CLI Side By Side
| Task | GitHub Web UI | GitHub CLI |
|---|---|---|
| Create repo | Click New repository | gh repo create |
| Open PR | Click Compare & pull request | gh pr create |
| Review PR locally | Copy branch commands | gh pr checkout <number> |
| Publish release | Open Releases page | gh release create |
Tip
ghdoes not replace Git. You still usegit add,git commit,git push, and other Git commands for version control.ghhandles GitHub-specific actions.
Pull Requests
A pull request is where collaboration happens on GitHub.
Pull requests are used to:
- Propose changes.
- Discuss implementation.
- Run automated checks.
- Review code.
- Request changes.
- Approve and merge work.
Anatomy Of A Strong Pull Request
| Section | What To Include |
|---|---|
| Title | A short summary of the change |
| Description | What changed and why |
| Screenshots | Before/after images for UI changes |
| Testing | Commands run and scenarios checked |
| Related issues | Links such as Closes #42 |
| Risks | Anything reviewers should inspect carefully |
Example Pull Request Template
## Summary
- Add profile editing screen
- Validate display name before saving
- Show success message after update
## Testing
- [ ] Ran unit tests
- [ ] Tested profile update in browser
- [ ] Checked validation errors
## Screenshots
Add screenshots or screen recordings here for UI changes.
## Related Issues
Closes #42
Tip
Use draft pull requests when your work is not ready for final review but you want early feedback or CI results.
Review Etiquette
For authors:
- Keep PRs small enough to review.
- Explain the reason behind non-obvious choices.
- Respond to comments calmly and specifically.
- Push follow-up commits instead of closing and reopening PRs.
For reviewers:
- Review the behavior, not only the code style.
- Ask questions before assuming intent.
- Separate required changes from optional suggestions.
- Be clear about what must change before merge.
GitHub Team Workflows
Professional repositories usually add guardrails so important branches stay stable.
Recommended Team Workflow
mainis protected.- Work happens on feature branches.
- Changes go through pull requests.
- CI checks must pass before merging.
- Reviews are required before merging.
- The team agrees on merge, squash, or rebase rules.
- Merged branches are deleted.
flowchart LR
A["main<br/>protected"] --> B["feature branch"]
B --> C["commits"]
C --> D["push"]
D --> E["pull request"]
E --> F["review + CI"]
F --> G["merge"]
G --> A
Protected Branches And Rulesets
Branch protection and GitHub rulesets help teams enforce the workflow automatically.
| Protection | What It Does | Why Teams Use It |
|---|---|---|
| Require pull requests | Blocks direct pushes to protected branches | Ensures review happens |
| Required reviews | Requires approval before merge | Improves code quality and shared ownership |
| Required status checks | Requires CI checks to pass | Prevents broken builds from merging |
| Restrict force pushes | Prevents rewriting important remote history | Protects teammates' work |
| Restrict deletions | Prevents accidental branch deletion | Protects release and main branches |
| Rulesets | Apply branch or tag rules across selected patterns | Centralizes policy for larger repositories |
Important
Direct pushes to
mainare convenient in small personal projects, but most teams protectmainso production-ready history is reviewed, tested, and traceable.
GitHub Actions And CI
Pull requests often run automated checks before they can be merged.
Common CI checks include:
- Unit tests.
- Integration tests.
- Linting.
- Formatting.
- Type checking.
- Build verification.
- Security or dependency scanning.
- Deployment previews.
flowchart LR
A["Open PR"] --> B["GitHub Actions starts"]
B --> C["Run tests"]
B --> D["Run lint"]
B --> E["Build project"]
C --> F["Checks pass?"]
D --> F
E --> F
F -->|yes| G["Ready for review / merge"]
F -->|no| H["Fix branch and push again"]
Note
CI does not replace human review. It catches repeatable checks so reviewers can focus on behavior, design, maintainability, and risk.
Before Opening A Pull Request
git statusis clean or only expected files are changed.- Tests pass locally, if the project has tests.
- Code is formatted.
- Commit messages are clear.
- Branch is up to date with
main. - PR description explains what changed and why.
- Screenshots or recordings are included for UI changes.
Before Merging
- Code review is complete.
- CI checks passed.
- No unresolved comments remain.
- Branch is up to date.
- The merge strategy matches the team's workflow.
- Release notes or documentation are updated if needed.
Merging, Squashing, And Rebasing
Combining branches is one of the most important Git skills.
Strategy Comparison
| Strategy | Command Or Action | Best For | What Happens | Main Risk |
|---|---|---|---|---|
| Merge commit | git merge feature/x |
Preserving branch history | Keeps the feature branch shape in history | History can be more detailed than some teams want |
| Squash merge | GitHub squash button or git merge --squash |
Turning many small commits into one clean feature commit | Combines multiple commits into one | Individual commit detail is lost |
| Rebase | git rebase main |
Cleaning up a personal feature branch | Replays commits on top of a new base | Rewrites commits |
| Fast-forward | Automatic when possible | Simple branch movement | Moves the branch pointer forward | Only possible when histories have not diverged |
Important
Merge preserves branch history. Rebase creates a cleaner linear history but rewrites commits. Squash combines multiple commits into one. Avoid rebasing shared branches unless the team explicitly expects it.
Merge A Branch Locally
git switch main
git pull
git merge feature/search
git push
Squash Merge Locally
git switch main
git pull
git merge --squash feature/search
git commit -m "Add search feature"
git push
Rebase Your Branch Onto Main
git switch feature/search
git fetch origin
git rebase origin/main
If conflicts happen, resolve them, then continue:
git add .
git rebase --continue
Cancel a rebase:
git rebase --abort
Caution
Rebasing rewrites commit history. Avoid rebasing shared branches unless your team expects it. If you rebase a branch that was already pushed, you may need
git push --force-with-lease.
Safer Force Push
git push --force-with-lease
Important
Prefer
--force-with-leaseover--force. It refuses to overwrite remote work if someone else pushed new commits while you were working.
You usually need it after rebasing a branch that was already pushed:
git switch feature/search
git fetch origin
git rebase origin/main
git push --force-with-lease
Warning
Do not force push shared branches such as
main,develop, or release branches unless your team has explicitly agreed on that action.
Undoing Changes Safely
Undo commands are not interchangeable. Choose based on where the change currently lives.
Safe And Dangerous Commands
| Safer Command | Why It Is Usually Safe |
|---|---|
git status |
Only reads repository state |
git diff |
Only shows changes |
git fetch |
Downloads remote history without changing your files |
git restore --staged |
Unstages changes but keeps file edits |
git revert |
Adds a new commit instead of rewriting published history |
| Dangerous Command | What It Can Change | Why To Be Careful |
|---|---|---|
git reset --hard |
Files, staging area, local history | Can delete local work |
git push --force |
Remote history | Can overwrite teammates' commits |
git clean -fd |
Untracked files and folders | Can delete files Git is not tracking |
| Rewriting published tags | Remote release history | Can confuse users who already downloaded a release |
Caution
Dangerous does not mean forbidden. It means slow down, check your state, and make a backup branch first.
Reset Vs Restore Vs Revert
| Situation | Recommended Command | Why |
|---|---|---|
| You staged a file by mistake | git restore --staged file.txt |
Keeps your edits but removes them from the next commit |
| You want to discard one file's uncommitted edits | git restore file.txt |
Restores the file from the latest commit |
| You made a local commit but have not pushed | git reset --soft HEAD~1 |
Removes the commit while keeping changes staged |
| You pushed a bad commit | git revert HEAD |
Creates a safe reversing commit |
| You need to discard all local work | git reset --hard |
Powerful, but destructive |
Emergency Checklist Before Destructive Commands
Before reset --hard, rebase, clean, force push, or tag rewriting:
- Run
git status. - Run
git log --oneline -5. - Create a backup branch.
- Only then consider the destructive command.
git status
git log --oneline -5
git branch backup/before-fix
Tip
A backup branch is cheap. It gives you a named pointer back to your current work if the next command does something surprising.
Resolving Merge Conflicts
A merge conflict happens when Git cannot automatically combine changes.
Common Causes
- Two branches edited the same lines.
- One branch deleted a file that another branch edited.
- A file was renamed differently in two branches.
- Large formatting changes touched many lines.
What Conflict Markers Look Like
<<<<<<< HEAD
Current branch version
=======
Incoming branch version
>>>>>>> feature/search
Conflict Resolution Workflow
- Run the command that caused the conflict, such as
git mergeorgit rebase. - Check status.
- Open each conflicted file.
- Choose the correct final content.
- Remove conflict markers.
- Stage resolved files.
- Continue the merge or rebase.
flowchart LR
A["Conflict"] --> B["Open conflicted file"]
B --> C["Choose final content"]
C --> D["Remove conflict markers"]
D --> E["git add"]
E --> F["commit or continue rebase"]
git status
git add path/to/resolved-file.js
git commit
For a rebase:
git add path/to/resolved-file.js
git rebase --continue
Abort If Needed
Abort a merge:
git merge --abort
Abort a rebase:
git rebase --abort
Warning
Never commit files that still contain
<<<<<<<,=======, or>>>>>>>. Those markers are not valid application code; they are Git asking you to decide.
Conflict Prevention Tips
- Pull or fetch frequently.
- Keep branches short-lived.
- Avoid massive formatting-only changes in feature PRs.
- Split refactors from behavior changes.
- Communicate when multiple people edit the same files.
GitHub Issues
Issues are GitHub's built-in way to track tasks, bugs, feature requests, and discussions.
Good Issues Include
| Type | Useful Details |
|---|---|
| Bug report | Steps to reproduce, expected behavior, actual behavior, environment |
| Feature request | Problem, proposed solution, alternatives |
| Task | Goal, acceptance criteria, owner |
| Documentation | Page or section affected, missing information |
Example Bug Report
## Description
The checkout button becomes disabled after applying a valid discount code.
## Steps To Reproduce
1. Add an item to cart.
2. Apply discount code `SAVE10`.
3. Click checkout.
## Expected Behavior
The checkout flow should continue.
## Actual Behavior
The checkout button remains disabled.
## Environment
- Browser: Chrome
- OS: Windows 11
- App version: v1.4.2
Link Issues To Pull Requests
Use keywords in PR descriptions:
Closes #42
Fixes #108
Resolves #215
When the PR merges, GitHub automatically closes the linked issue.
Tip
Labels such as
bug,documentation,good first issue, andhelp wantedmake repositories easier to navigate for contributors.
Forking Repositories
A fork is your personal copy of someone else's GitHub repository.
Forks are useful when:
- You do not have write access to the original repository.
- You want to propose an open source contribution.
- You want to experiment independently.
Fork Workflow
Original repo -> Your fork -> Your local clone -> Pull request back to original repo
flowchart LR
A["Original repository"] --> B["Fork on your GitHub account"]
B --> C["Clone your fork"]
C --> D["Add upstream remote"]
D --> E["Create branch"]
E --> F["Push to your fork"]
F --> G["Open pull request upstream"]
Clone Your Fork
git clone git@github.com:your-username/project.git
cd project
Add The Original Repository As Upstream
git remote add upstream git@github.com:original-owner/project.git
git remote -v
You should see both:
origin git@github.com:your-username/project.git
upstream git@github.com:original-owner/project.git
Keep Your Fork Updated
git fetch upstream
git switch main
git merge upstream/main
git push origin main
Alternative with rebase:
git fetch upstream
git switch main
git rebase upstream/main
git push origin main
Important
In a fork workflow,
originusually points to your fork, whileupstreampoints to the original project.
Open Source Contribution Workflow
Open source contribution becomes much easier when you follow a predictable path.
Before You Start
- Read the project README.
- Read
CONTRIBUTING.mdif it exists. - Check open issues and existing pull requests.
- Confirm whether the maintainers want the change.
- Start with a small, focused contribution.
Tip
For bigger changes, open an issue first. Maintainers can confirm the direction before you spend hours implementing something they may not accept.
Step-By-Step Contribution
- Fork the repository on GitHub.
- Clone your fork.
- Add the original repository as
upstream. - Create a new branch.
- Make focused changes.
- Run tests and formatting.
- Commit with a clear message.
- Push to your fork.
- Open a pull request to the original repository.
- Respond to review feedback.
git clone git@github.com:your-username/project.git
cd project
git remote add upstream git@github.com:original-owner/project.git
git switch -c fix/readme-typo
# edit files
git status
git diff
git add README.md
git commit -m "Fix README installation typo"
git push -u origin fix/readme-typo
Open Source PR Description Example
## Summary
Fixes a typo in the installation instructions where `npm install` was shown as `npm isntall`.
## Why
The typo could confuse new users following the setup guide.
## Testing
- Verified the rendered README locally.
Closes #123
Note
Many valuable open source contributions are documentation, tests, examples, and bug reports. You do not need to rewrite the core project to be helpful.
Tags, Releases, And Semantic Versioning
Tags mark important commits. Releases are GitHub pages built around tags, often including changelogs and downloadable assets.
Create A Lightweight Tag
git tag v1.0.0
git push origin v1.0.0
Create An Annotated Tag
Annotated tags include metadata and a message. They are recommended for releases.
git tag -a v1.0.0 -m "Release version 1.0.0"
git push origin v1.0.0
Push All Tags
git push origin --tags
List Tags
git tag
git tag -l "v1.*"
Delete A Tag
Delete locally:
git tag -d v1.0.0
Delete remotely:
git push origin :refs/tags/v1.0.0
Warning
Avoid moving or rewriting published tags. Someone may already have downloaded that version. Prefer creating a new patch version, such as
v1.0.1.
Semantic Versioning
Semantic Versioning uses this format:
MAJOR.MINOR.PATCH
Example:
v2.4.1
| Version Part | Increase When | Example |
|---|---|---|
MAJOR |
You make incompatible breaking changes | v1.8.0 -> v2.0.0 |
MINOR |
You add backward-compatible functionality | v1.8.0 -> v1.9.0 |
PATCH |
You make backward-compatible bug fixes | v1.8.0 -> v1.8.1 |
Release Checklist
- Tests pass.
- Documentation is updated.
- Changelog is written.
- Version number is correct.
- Tag is created.
- GitHub Release notes are published.
- Deployment or package publishing is complete.
Professional Workflow Examples
Teams choose different branching strategies depending on release cadence, team size, and deployment style.
Branching Strategy Comparison
| Workflow | Best For | Basic Shape | Tradeoff |
|---|---|---|---|
| GitHub Flow | Web apps, SaaS, continuous delivery | main plus short-lived feature branches |
Simple, but relies on strong tests and reviews |
| Git Flow | Scheduled releases, multiple supported versions | main, develop, feature, release, and hotfix branches |
Structured, but heavier |
| Trunk-Based Development | Fast-moving teams with strong CI and feature flags | Very short branches merged quickly into trunk | Requires discipline and automation |
GitHub Flow
gitGraph
commit id: "main"
branch feature
checkout feature
commit id: "work"
commit id: "tests"
checkout main
merge feature
commit id: "deploy"
Use this when the team deploys frequently and wants a simple model: branch, commit, PR, review, merge, deploy.
Git Flow
gitGraph
commit id: "main"
branch develop
checkout develop
commit id: "integration"
branch feature
checkout feature
commit id: "feature"
checkout develop
merge feature
branch release
checkout release
commit id: "release prep"
checkout main
merge release
Use this when releases are scheduled, stabilized, or maintained across multiple versions.
Trunk-Based Development
gitGraph
commit id: "trunk"
branch small_change
checkout small_change
commit id: "tiny commit"
checkout main
merge small_change
commit id: "CI green"
Use this when branches are short-lived, CI is reliable, and unfinished work can be hidden behind feature flags.
Solo Project Workflow
Best for personal projects, prototypes, and small tools.
git status
git pull
git add .
git commit -m "Add CSV export"
git push
Recommended habits:
- Commit when a small unit of work is complete.
- Push at the end of each session.
- Use branches for risky changes.
- Tag stable milestones.
Team Feature Branch Workflow
Best for most professional teams.
git switch main
git pull
git switch -c feature/billing-history
# edit files
git add .
git commit -m "Add billing history table"
git push -u origin feature/billing-history
Then open a pull request and merge after review.
Hotfix Workflow
Best for urgent production fixes.
git switch main
git pull
git switch -c hotfix/payment-timeout
# fix and test
git add .
git commit -m "Fix payment timeout handling"
git push -u origin hotfix/payment-timeout
After review and merge, create a patch release:
git switch main
git pull
git tag -a v1.4.3 -m "Release v1.4.3"
git push origin v1.4.3
Documentation-Only Workflow
git switch -c docs/update-install-guide
# edit docs
git add README.md
git commit -m "Clarify installation guide"
git push -u origin docs/update-install-guide
Tip
Documentation PRs are still codebase changes. Review formatting, links, examples, and rendered output before opening the PR.
Conventional Commit Examples
Some teams use Conventional Commits.
Bad commit messages:
update
fix
changes
final
Better commit messages:
feat: add password reset flow
fix: prevent crash when avatar is missing
docs: update API authentication examples
test: add checkout validation coverage
refactor: simplify invoice total calculation
chore: update development dependencies
Use the imperative mood when possible: write Add profile page, not Added profile page or Adds profile page. The commit message should read like an instruction that applies the change.
For larger changes, use a subject line, a blank line, and a body:
fix: prevent duplicate login redirect
The login callback could run twice when the session refresh completed
while the redirect handler was still active. Guard the redirect so the
user lands on the dashboard once.
Practical Mini Project
Use this practice flow in a test repository so mistakes are harmless.
1. Create A Repository
mkdir git-practice
cd git-practice
git init
2. Add A README And Make The First Commit
echo "# Git Practice" > README.md
git add README.md
git commit -m "docs: add initial README"
3. Create A Branch And Edit A File
git switch -c feature/add-notes
echo "Learning Git one safe command at a time." >> README.md
git status
git diff
git add README.md
git commit -m "docs: add practice note"
4. Push The Branch
Create an empty GitHub repository, then connect and push:
git remote add origin git@github.com:your-username/git-practice.git
git push -u origin main
git push -u origin feature/add-notes
Optional with GitHub CLI:
gh repo create git-practice --public --source=. --remote=origin --push
gh pr create --fill
5. Open A Pull Request
Open a PR from feature/add-notes into main. In the description, explain what changed and how you checked it.
6. Practice A Simple Conflict
In one branch:
git switch main
echo "Main branch version." >> README.md
git add README.md
git commit -m "docs: add main branch note"
In another branch:
git switch feature/add-notes
echo "Feature branch version." >> README.md
git add README.md
git commit -m "docs: add feature branch note"
Now merge main into the feature branch and resolve the conflict:
git merge main
git status
Open README.md, choose the final text, remove conflict markers, then finish:
git add README.md
git commit -m "docs: resolve README conflict"
Best Practices
Commit Best Practices
- Keep commits focused.
- Write clear messages.
- Review diffs before committing.
- Avoid committing generated files unless the project expects them.
- Avoid mixing formatting, refactoring, and behavior changes in one commit.
Branch Best Practices
- Branch from the latest
main. - Use descriptive names.
- Keep branches short-lived.
- Delete merged branches.
- Avoid committing directly to protected branches.
Pull Request Best Practices
- Keep PRs small enough to review.
- Explain the reason for the change.
- Include testing notes.
- Add screenshots for UI changes.
- Link related issues.
- Respond to review feedback with context.
Ignore Files With .gitignore
A .gitignore file tells Git which untracked files should stay out of the repository.
# Dependencies
node_modules/
# Environment and secrets
.env
.env.local
# Build and test output
dist/
build/
coverage/
# Logs
*.log
# OS and editor files
.DS_Store
.idea/
.vscode/
Important
.gitignoredoes not affect files that are already tracked. If a file was already committed, Git will keep tracking it until you remove it from the index.
Stop tracking an already-committed file while keeping it locally:
git rm --cached file-name
git commit -m "Stop tracking ignored file"
GitHub also provides built-in .gitignore templates for many languages and frameworks. The template collection is available at github.com/github/gitignore.
Normalize Files With .gitattributes
.gitattributes helps teams reduce cross-platform noise, especially line-ending changes between Windows, macOS, and Linux.
# Let Git normalize text files automatically
* text=auto
# Shell scripts should use LF
*.sh text eol=lf
# Windows batch files should use CRLF
*.bat text eol=crlf
# Treat common binary files as binary
*.png binary
*.jpg binary
*.pdf binary
Tip
Use
.gitattributeswhen teammates on different operating systems see large diffs caused only by line endings.
Basic Security Best Practices
- Never commit passwords, tokens, API keys, or private keys.
- Use
.envfiles locally and add them to.gitignore. - Rotate secrets immediately if they are committed.
- Use GitHub secret scanning where available.
- Review dependency updates before merging.
.env
.env.local
*.pem
*.key
node_modules/
dist/
coverage/
*.log
Caution
Deleting a secret from the latest commit is not enough if it was already pushed. The secret still exists in history. Rotate the secret immediately.
Repository Hygiene
- Keep README instructions current.
- Add a license for public projects.
- Use issue and PR templates.
- Keep CI checks meaningful.
- Archive abandoned experiments if they no longer represent the project.
Security
Git history is durable. That is useful for recovery, but dangerous when secrets are committed.
Secrets And Rotation
If a secret is committed:
- Rotate the exposed secret immediately.
- Remove the secret from the repository.
- Commit the cleanup.
- If needed, rewrite history carefully with a purpose-built tool.
- Tell collaborators to re-clone or repair local history if history was rewritten.
Caution
Deleting a secret from the latest commit is not enough. If it was committed earlier, it may still exist in Git history, forks, caches, logs, or clones.
Secret Scanning
GitHub can detect many common token patterns with secret scanning. Enable it where available, but do not rely on scanning as your only defense.
Good habits:
- Store local secrets in
.envfiles. - Add secret files to
.gitignore. - Use environment variables in applications and CI.
- Review diffs before committing.
- Rotate any exposed credential immediately.
Credential Managers
Credential managers store HTTPS credentials or tokens securely so you do not paste them repeatedly.
Common options:
- Git Credential Manager, included with Git for Windows and available cross-platform.
- macOS Keychain integration.
- Linux secret service or credential helpers.
SSH Key Safety
- Never commit private keys such as
id_ed25519. - Public keys ending in
.pubare safe to upload to GitHub. - Use a passphrase for important keys.
- Remove unused keys from GitHub.
- Prefer separate keys for personal and work accounts when policies require it.
Private Keys And .gitignore
*.pem
*.key
id_rsa
id_ed25519
Important
If a private key is committed, assume it is compromised. Remove it from GitHub, rotate anything it could access, and generate a new key.
Common Mistakes
Mistake: Committing Everything Blindly
git add .
git commit -m "update"
This can accidentally include secrets, debug files, or unrelated changes.
Better:
git status
git diff
git add src/app.js README.md
git commit -m "Add app startup instructions"
Mistake: Committing .env Files
.env files often contain API keys, database URLs, or tokens.
Better:
echo ".env" >> .gitignore
git status
If .env was already committed, rotate the secret and stop tracking the file:
git rm --cached .env
git commit -m "Stop tracking local environment file"
Mistake: Working Directly On main
Working on main makes it easier to mix stable code with unfinished work.
Better:
git switch main
git pull
git switch -c feature/new-dashboard
Mistake: Making Huge Commits With Unclear Purpose
Huge commits are harder to review and harder to revert.
Better:
- Commit one logical change at a time.
- Split formatting from behavior changes.
- Use
git add -pto stage only part of a file.
Mistake: Pulling Without Knowing Your Local State
Always check status first:
git status
git pull
Mistake: Ignoring git status
git status usually tells you exactly what Git needs next. Running commands without checking status often makes simple problems feel larger than they are.
Mistake: Not Reading Git Error Messages
Git errors are dense, but they often contain the command you need next. Read the first line, then the advice lines. If a message mentions non-fast-forward, public key, detached HEAD, or unrelated histories, see How To Read Common Git Errors.
Mistake: Using --force Carelessly
git push --force
Better:
git push --force-with-lease
Warning
Force pushing shared branches can erase other people's work from the remote branch. Use protected branches for important branches like
main.
Mistake: Ignoring Merge Conflict Markers
Search before committing:
git diff --check
You can also search files:
grep -R -E "<<<<<<<|=======|>>>>>>>" .
On Windows PowerShell:
Get-ChildItem -Recurse -File | Select-String -Pattern "<<<<<<<|=======|>>>>>>>"
Mistake: Committing Large Files
Large files make repositories slow.
Better options:
- Store build artifacts outside Git.
- Use GitHub Releases for downloadable binaries.
- Use Git LFS for large files that must be versioned.
Mistake: Committing Dependencies Or Build Output
Folders such as node_modules/, dist/, build/, and coverage/ usually do not belong in Git.
Better:
node_modules/
dist/
build/
coverage/
Troubleshooting
This section is for the moments when Git feels scary.
Important
Before running destructive commands, copy the output of
git statusandgit log --oneline -5. That small snapshot can help you recover or ask for help clearly.
I Changed Files But Have Not Committed Yet
See changed files:
git status
git diff
Discard changes in one file:
git restore path/to/file.txt
Discard all uncommitted tracked file changes:
git restore .
Caution
git restore .discards local uncommitted changes in tracked files. Use it only when you are sure you do not need those edits.
I Staged Files By Mistake
Unstage everything but keep the file changes:
git restore --staged .
Unstage one file:
git restore --staged path/to/file.txt
I Committed But Have Not Pushed Yet
Fix the last commit message:
git commit --amend -m "Better commit message"
Add a forgotten file to the last commit:
git add forgotten-file.js
git commit --amend --no-edit
Undo the commit but keep changes staged:
git reset --soft HEAD~1
Undo the commit and keep changes unstaged:
git reset HEAD~1
Discard the commit and its changes:
git reset --hard HEAD~1
Warning
git reset --harddeletes local changes from your working tree. If you are unsure, do not use it yet.
I Pushed A Bad Commit
Safest option: create a new commit that reverses the bad one.
git revert HEAD
git push
Revert a specific commit:
git log --oneline
git revert abc1234
git push
Tip
git revertis usually best for shared branches because it preserves history instead of rewriting it.
I Want To Undo The Last Commit
If the commit was not pushed and you want to keep the changes:
git reset --soft HEAD~1
If the commit was pushed:
git revert HEAD
git push
Important
Use
resetmainly for local, unpushed commits. Userevertfor commits that other people may already have.
My Push Was Rejected
Common message:
rejected because the remote contains work that you do not have locally
Safe workflow:
git fetch origin
git status
git pull --rebase
git push
If conflicts happen, resolve them, then:
git add .
git rebase --continue
git push
I Have A Merge Conflict
Start with status:
git status
Then open each conflicted file, choose the final content, remove conflict markers, and finish:
git add path/to/file
git commit
If the conflict happened during rebase:
git add path/to/file
git rebase --continue
See Resolving Merge Conflicts for the full workflow.
I Need To Switch Branches But Have Unfinished Work
Save work temporarily:
git stash push -m "WIP: dashboard filters"
git switch other-branch
Bring the work back:
git stash list
git stash pop
Note
Stash is temporary storage, not a replacement for commits. See Stashing Unfinished Work for the full command set.
I Need To Rename A Branch
Rename the current local branch:
git branch -m new-branch-name
Rename another local branch:
git branch -m old-branch-name new-branch-name
If the old branch was already pushed:
git push origin --delete old-branch-name
git push -u origin new-branch-name
I Am In Detached HEAD State
Detached HEAD means you checked out a specific commit instead of a branch.
If you only wanted to inspect history:
git switch main
If you made changes and want to keep them:
git switch -c rescue/my-work
git add .
git commit -m "Save detached HEAD work"
If you are unsure whether you made changes:
git status
git switch -c backup/detached-head-work
I Accidentally Committed To main
If you have not pushed:
git branch feature/rescue-work
git reset --hard origin/main
git switch feature/rescue-work
If origin/main is not available:
git branch feature/rescue-work
git reset --soft HEAD~1
git switch -c feature/rescue-work
git commit -m "Move work to feature branch"
Caution
Be careful with
reset --hard. Confirm the target branch and commit before running it.
I Deleted A File By Mistake
If not committed:
git restore path/to/deleted-file.txt
If committed:
git revert HEAD
Restore a file from a specific commit:
git restore --source abc1234 -- path/to/file.txt
I Need To Discard One File
Discard uncommitted edits in one tracked file:
git restore path/to/file.txt
Discard staged changes for one file but keep the edits:
git restore --staged path/to/file.txt
I Need To Unstage One File
git restore --staged path/to/file.txt
The file remains edited in your working directory.
I Need A Clean Copy Of The Remote Branch
git fetch origin
git reset --hard origin/main
Caution
This replaces your local branch with
origin/mainand discards local commits and changes that are not on the remote branch.
I Need To Update My Fork
Fetch the original repository and update your fork's main branch:
git fetch upstream
git switch main
git merge upstream/main
git push origin main
If your project prefers rebase:
git fetch upstream
git switch main
git rebase upstream/main
git push origin main
See Forking Repositories and Open Source Contribution Workflow for the full context.
I Committed A Secret
- Rotate the secret immediately.
- Remove the secret from the code.
- Commit the cleanup.
- If necessary, rewrite history with a specialized tool such as
git filter-repo. - Coordinate with anyone who cloned the repository.
Important
Treat exposed secrets as compromised even if you delete them quickly.
I Need To Recover Lost Work
Use reflog to find where your branch or HEAD used to point:
git reflog
Create a recovery branch from the commit you want:
git switch -c recovery-branch abc1234
See Use Reflog To Recover Lost Commits for more examples.
I Cannot Authenticate With GitHub
Check remote URL:
git remote -v
For SSH:
ssh -T git@github.com
For HTTPS:
- Use a personal access token when prompted for a password.
- Confirm Git Credential Manager is installed.
- Remove old cached credentials if necessary.
How To Read Common Git Errors
Git errors often look intimidating because they include implementation details. Start by identifying the category.
| Error Text | What It Usually Means | First Thing To Try |
|---|---|---|
fatal: not a git repository |
You are not inside a Git repository folder | pwd, ls, then cd into the project |
rejected non-fast-forward |
The remote branch has commits you do not have | git fetch origin, then rebase or merge |
Permission denied (publickey) |
SSH authentication failed | Check SSH Setup For GitHub and run ssh -T git@github.com |
CONFLICT |
Git could not combine files automatically | Open conflicted files and resolve markers |
detached HEAD |
You checked out a commit instead of a branch | git switch main or create a rescue branch |
refusing to merge unrelated histories |
Two repositories have different roots | Confirm you connected the correct remote before using --allow-unrelated-histories |
fatal: not a git repository
You are probably in the wrong folder.
pwd
ls
cd path/to/project
git status
rejected non-fast-forward
Your push was rejected because GitHub has commits your local branch does not have.
git fetch origin
git pull --rebase
git push
Permission denied (publickey)
GitHub did not accept your SSH key.
ssh -T git@github.com
git remote -v
Common fixes:
- Add your public key to GitHub.
- Add your private key to the SSH agent.
- Confirm the remote URL uses SSH.
- Confirm you are using the right GitHub account.
CONFLICT
Git found overlapping changes.
git status
Then follow Resolving Merge Conflicts.
Detached HEAD
You are looking at a specific commit rather than a branch.
Exit safely:
git switch main
Save work first:
git switch -c recovery/detached-work
git add .
git commit -m "Save detached HEAD work"
refusing to merge unrelated histories
This often happens when a local repository and a GitHub repository were both initialized separately.
First, verify the remote is correct:
git remote -v
git log --oneline --all --graph -10
Only use this if you intentionally want to combine unrelated histories:
git pull origin main --allow-unrelated-histories
Warning
Do not use
--allow-unrelated-historiesas a reflex. It is a sign that your local and remote repositories may not be the same project.
Cheat Sheets
Daily Commands
| Goal | Command |
|---|---|
| Show repository state | git status |
| Show unstaged changes | git diff |
| Show staged changes | git diff --staged |
| Stage all changes | git add . |
| Stage one file | git add path/to/file |
| Commit | git commit -m "Message" |
| Pull latest changes | git pull |
| Push commits | git push |
| Create branch | git switch -c branch-name |
| Switch branch | git switch branch-name |
| View history | git log --oneline --graph --decorate |
Undo Commands
| Situation | Safe Command | Notes |
|---|---|---|
| Unstage files | git restore --staged . |
Keeps file changes |
| Discard uncommitted changes | git restore . |
Tracked files only |
| Fix last unpushed commit | git commit --amend |
Rewrites last local commit |
| Undo last unpushed commit, keep changes | git reset --soft HEAD~1 |
Changes stay staged |
| Undo pushed commit safely | git revert HEAD |
Creates a new reversing commit |
| Recover lost commit | git reflog |
Find previous HEAD positions |
Branch Commands
| Goal | Command |
|---|---|
| List local branches | git branch |
| List all branches | git branch -a |
| Create branch | git switch -c feature/name |
| Rename current branch | git branch -m new-name |
| Delete merged branch | git branch -d branch-name |
| Delete remote branch | git push origin --delete branch-name |
Remote Commands
| Goal | Command |
|---|---|
| Show remotes | git remote -v |
| Add origin | git remote add origin URL |
| Change origin URL | git remote set-url origin URL |
| Fetch remote updates | git fetch origin |
| Push new branch | git push -u origin branch-name |
| See remote branches | git branch -r |
Stash Commands
| Goal | Command |
|---|---|
| Stash current changes | git stash |
| Stash with message | git stash push -m "message" |
| List stashes | git stash list |
| Apply latest stash and remove it | git stash pop |
| Apply latest stash but keep it | git stash apply |
| Drop latest stash | git stash drop |
Tag Commands
| Goal | Command |
|---|---|
| Create annotated tag | git tag -a v1.0.0 -m "Release v1.0.0" |
| Push tag | git push origin v1.0.0 |
| Push all tags | git push origin --tags |
| List tags | git tag |
| Delete local tag | git tag -d v1.0.0 |
| Delete remote tag | git push origin :refs/tags/v1.0.0 |
Printable Emergency Cheat Sheet
Start Here
git status
git log --oneline -5
I Need To Undo Something
# Unstage files
git restore --staged .
# Discard uncommitted tracked changes
git restore .
# Undo last local commit but keep changes
git reset --soft HEAD~1
# Safely undo a pushed commit
git revert HEAD
git push
I Need To Save Work Temporarily
git stash push -m "WIP: describe work"
git stash pop
I Need To Recover Lost Work
git reflog
git switch -c rescue-work abc1234
Advanced Tips For Power Users
Advanced Git is mostly about precision, recovery, and speed.
Use Reflog To Recover Lost Commits
git reflog shows where HEAD has been recently. It is one of Git's best safety nets for recovering commits after resets, rebases, and accidental branch deletion.
git reflog
Recover a commit by creating a branch from it:
git switch -c recovery-branch abc1234
Tip
Reflog is local to your machine. It can rescue work after resets, rebases, and accidental branch deletion.
Cherry-Pick A Commit
Apply one commit from another branch:
git cherry-pick abc1234
Good for:
- Moving one bug fix to a release branch.
- Copying a small change without merging the entire branch.
- Applying a hotfix to multiple supported versions.
Clean Up Local Commits With Interactive Rebase
Interactive rebase lets you edit a sequence of commits.
git rebase -i HEAD~4
Common actions:
| Action | Meaning |
|---|---|
pick |
Keep the commit as-is |
reword |
Keep the commit but change its message |
edit |
Stop at the commit so you can change it |
squash |
Combine the commit with the previous commit and edit the message |
fixup |
Combine the commit with the previous commit and discard this message |
drop |
Remove the commit |
Warning
Interactive rebase rewrites history. Use it mainly for local or personal feature branches. Avoid it on shared branches unless your team explicitly expects it.
Find The Commit That Introduced A Bug
Use binary search with git bisect.
git bisect start
git bisect bad
git bisect good v1.2.0
Git checks out commits. You test each one and mark it:
git bisect good
git bisect bad
Finish:
git bisect reset
Use Worktrees For Multiple Branches At Once
Worktrees let you check out multiple branches in separate folders without cloning again.
git worktree add ../project-hotfix hotfix/payment-timeout
List worktrees:
git worktree list
Remove a worktree:
git worktree remove ../project-hotfix
Use Sparse Checkout For Large Repositories
Sparse checkout is useful when a repository is very large and you only need part of it.
git clone --filter=blob:none --sparse git@github.com:owner/repo.git
cd repo
git sparse-checkout set path/to/folder
Add another folder later:
git sparse-checkout add another/path
Note
Sparse checkout is common in monorepos. For small repositories, a normal clone is simpler.
Create Useful Aliases
git config --global alias.s "status"
git config --global alias.sw "switch"
git config --global alias.br "branch"
git config --global alias.lg "log --oneline --graph --decorate --all"
Then use:
git s
git lg
Optional productivity aliases:
git config --global alias.last "log -1 --stat"
git config --global alias.unstage "restore --staged"
git config --global alias.visual "log --graph --decorate --oneline --all"
Sign Commits
Signed commits prove that commits came from a verified key. GitHub can show a Verified badge for correctly signed commits.
GitHub supports signing with:
- SSH keys.
- GPG keys.
- S/MIME certificates.
Basic SSH signing example:
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
Basic GPG signing shape:
gpg --list-secret-keys --keyid-format=long
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
Note
Commit signing is optional for most beginners. It is common in security-sensitive projects, enterprise repositories, and some open source communities.
Use .gitignore Correctly
Example .gitignore:
# Dependencies
node_modules/
vendor/
# Environment files
.env
.env.local
# Build output
dist/
build/
coverage/
# Logs
*.log
npm-debug.log*
# OS/editor noise
.DS_Store
Thumbs.db
.vscode/
.idea/
If a file is already tracked, adding it to .gitignore will not untrack it.
git rm --cached path/to/file
Use Git Hooks
Git hooks run scripts during Git events, such as before a commit.
Common uses:
- Run formatters.
- Run tests.
- Prevent commits with secrets.
- Validate commit messages.
Common hook types:
| Hook | When It Runs | Common Use |
|---|---|---|
pre-commit |
Before Git creates a commit | Format, lint, scan for secrets |
commit-msg |
After the message is written, before commit completes | Validate commit message style |
Hook managers include tools such as Husky, Lefthook, and pre-commit.
Use Git LFS For Large Files
Git Large File Storage helps track large binary files without bloating normal Git history.
git lfs install
git lfs track "*.psd"
git add .gitattributes
git add design.psd
git commit -m "Track design file with Git LFS"
FAQ
Do I Need GitHub To Use Git?
No. Git works locally on your computer. GitHub hosts Git repositories online and adds collaboration features.
Should I Use HTTPS Or SSH?
Both are valid. HTTPS is often easier for beginners. SSH is convenient once configured, especially if you push frequently.
What Is The Difference Between git fetch And git pull?
git fetch downloads remote changes without changing your working branch. git pull downloads changes and integrates them into your branch.
What Is The Difference Between git merge And git rebase?
merge combines histories and preserves the branch structure. rebase moves your commits onto a new base and creates a more linear history.
Is Rebase Bad?
No. Rebase is powerful and useful, especially for local cleanup. It becomes risky when used on shared branches because it rewrites commit history.
What Is origin?
origin is the default name Git gives to the remote repository you cloned from.
What Is upstream?
In fork workflows, upstream usually means the original repository that your fork came from.
Why Does Git Say My Branch Has No Upstream?
Your local branch is not connected to a remote branch yet. Push with:
git push -u origin branch-name
What Should I Do Before Running A Dangerous Command?
Run:
git status
git log --oneline -5
If you are still unsure, create a backup branch:
git branch backup/before-risky-command
What Is The Safest Way To Undo A Pushed Commit?
Use git revert.
git revert HEAD
git push
Can I Change A Commit Message After Pushing?
Technically yes, but it rewrites history. For shared branches, avoid it unless your team agrees.
Why Is My Pull Request So Hard To Review?
It may be too large or mix unrelated changes. Try splitting formatting, refactoring, tests, and feature work into separate PRs.
Should Generated Files Be Committed?
It depends on the project. Source code usually belongs in Git. Build output, dependency folders, logs, and local environment files usually do not.
How Often Should I Commit?
Commit whenever you complete a meaningful unit of work. A good commit should be easy to describe in one sentence.
How Often Should I Push?
Push at least when you want backup, collaboration, CI results, or a pull request. Many developers push once a branch has a useful commit or at the end of a work session.
Glossary
| Term | Meaning |
|---|---|
| Branch | A separate line of development |
| Checkout | Older command for switching branches or restoring files |
| Clone | Download a repository and its history |
| Commit | A saved snapshot of changes |
| Conflict | A change Git cannot combine automatically |
| Fetch | Download remote changes without integrating them |
| Fork | Your copy of someone else's GitHub repository |
| HEAD | The current commit or branch position |
| Index | Another name for the staging area |
| Main | Common name for the default branch |
| Merge | Combine changes from one branch into another |
| Origin | Default name for the remote repository |
| Pull | Fetch and integrate remote changes |
| Pull Request | GitHub review process for proposed changes |
| Push | Upload local commits to a remote |
| Rebase | Replay commits on top of another base commit |
| Remote | A connected repository hosted elsewhere |
| Repository | A project tracked by Git |
| Reset | Move a branch pointer and optionally change staged or working files |
| Revert | Create a new commit that undoes another commit |
| Staging Area | The set of changes prepared for the next commit |
| Stash | Temporary storage for unfinished work |
| Tag | A named pointer to a specific commit, often a release |
| Upstream | Usually the original repository in a fork workflow |
Further Reading
- Official Git Documentation
- Git Book
- GitHub Docs
- GitHub CLI Manual
- GitHub Actions Documentation
- GitHub Rulesets Documentation
- GitHub Skills
- Semantic Versioning
- Conventional Commits
- Git Large File Storage
- Choose An Open Source License
What To Do Next
The fastest way to learn Git is to practice in a repository where nothing important can break.
- Create a test repository.
- Practice the daily workflow until it feels boring.
- Open a pull request from a feature branch.
- Create and resolve a small merge conflict.
- Practice undo commands:
restore,reset --soft, andrevert. - Learn
git reflogbefore you need it. - Make a small open-source documentation contribution.
Tip
Start with documentation fixes. They teach the open-source workflow without requiring you to understand an entire codebase first.
Final One-Page Cheat Sheet
Daily Workflow
git status
git pull
git switch -c feature/name
git add .
git commit -m "Add feature"
git push -u origin feature/name
Branch Workflow
git switch main
git pull
git switch -c feature/name
git push -u origin feature/name
Pull Request Workflow
branch -> commit -> push -> pull request -> review -> CI -> merge
Undo Workflow
| Need | Command |
|---|---|
| Unstage files | git restore --staged . |
| Discard one file | git restore file.txt |
| Undo local commit, keep changes | git reset --soft HEAD~1 |
| Undo pushed commit safely | git revert HEAD |
| Recover lost commit | git reflog |
Remote Workflow
git remote -v
git fetch origin
git pull
git push
Fork Workflow
git clone git@github.com:your-username/project.git
cd project
git remote add upstream git@github.com:original-owner/project.git
git fetch upstream
git switch -c fix/small-change
git push -u origin fix/small-change
Emergency Commands
git status
git log --oneline -5
git branch backup/before-fix
git restore --staged .
git restore .
git reset --soft HEAD~1
git revert HEAD
git stash
git reflog
Most Important Safety Rules
- Run
git statusbefore changing direction. - Read
git diffbefore committing. - Use branches for real work.
- Use
git revertfor pushed commits. - Avoid
git reset --hardunless you have a backup branch. - Prefer
git push --force-with-leaseovergit push --force. - Never commit secrets, private keys, dependency folders, or build output unless the project explicitly requires it.
Final Advice
Git rewards calm, careful habits:
- Check status often.
- Read diffs before committing.
- Use branches for meaningful work.
- Prefer safe undo commands on shared history.
- Ask Git what is happening before guessing.
git status
That command is your compass.