reference · git 2.4x · gh cli
Everything a developer needs to know about Git & GitHub
Git is the version control tool that runs on your machine. GitHub is a service built around it — hosting, pull requests, issues, and automation. This guide covers both: the commands you'll type daily, the workflow teams actually use, and what to do when something breaks.
01 Setup & identity
One-time configuration after installing Git or moving to a new machine.
IdentityTell Git who you are
$ git config --global user.name "Ada Lovelace"
$ git config --global user.email "ada@example.com"
$ git config --global init.defaultBranch main
$ git config --global core.editor "code --wait"
$ git config --list # see everything currently set
AuthenticationConnect to GitHub over SSH
$ ssh-keygen -t ed25519 -C "ada@example.com"
$ eval "$(ssh-agent -s)"
$ ssh-add ~/.ssh/id_ed25519
# paste ~/.ssh/id_ed25519.pub into GitHub → Settings → SSH and GPG keys
$ ssh -T git@github.com # verify — should greet you by username
gh auth login (below) or a personal access token as the password.
SigningVerified commits (optional)
$ git config --global commit.gpgsign true
$ git config --global user.signingkey <KEY-ID>
02 Core workflow
The loop you repeat dozens of times a day: change files, stage, commit, sync.
| Command | What it does |
|---|---|
git init | Turn the current folder into a Git repository. |
git clone <url> | Copy a remote repository, including its full history, to your machine. |
git status | Show what's changed, staged, and untracked. |
git add <file> | Stage a file's changes for the next commit. |
git add -p | Stage interactively, chunk by chunk — the safer default for mixed changes. |
git commit -m "…" | Save staged changes as a snapshot in history. |
git commit --amend | Fold new changes into the last commit instead of making a new one. |
git push | Send local commits to the remote. |
git pull | Fetch and merge the remote's new commits into your branch. |
ExampleFirst push of a new branch
$ git switch -c feature/search-filter
$ git add .
$ git commit -m "Add category filter to search"
$ git push -u origin feature/search-filter # -u links local ↔ remote branch
03 Branching & merging
Branches are just movable pointers to commits — cheap to make, cheap to throw away.
git branch
List, create, or delete branches. git branch -d name deletes safely; -D forces it.
git switch <branch>
Move to an existing branch. git switch -c name creates and moves in one step.
git merge <branch>
Bring another branch's commits into the current one, preserving both histories.
git rebase <branch>
Replay your commits on top of another branch — linear history, no merge commit.
Merge vs. rebaseWhen to use which
Merge preserves exactly what happened, including a merge commit — good for shared branches like main. Rebase rewrites your commits onto a new base — good for tidying a feature branch before opening a PR. Never rebase a branch other people have already pulled from.
$ git switch main && git pull
$ git switch feature/search-filter
$ git rebase main # replay feature commits on latest main
$ git rebase -i HEAD~3 # interactively squash/reorder the last 3 commits
Resolving a conflictWhat the markers mean
<<<<<<< HEAD
const timeout = 3000;
=======
const timeout = 5000;
>>>>>>> feature/search-filter
Edit the file down to the version you want, delete the marker lines, then:
$ git add path/to/file.js
$ git commit # finishes a merge
# — or, mid-rebase —
$ git rebase --continue
Cherry-pickTake one commit without the rest of a branch
$ git cherry-pick a1b2c3d
04 Remotes & syncing
A remote is just a named URL. origin is convention, not magic.
$ git remote -v # list remotes and their URLs
$ git remote add origin git@github.com:you/repo.git
$ git remote set-url origin <new-url> # fix a typo'd or migrated URL
$ git fetch --all --prune # update refs, drop deleted remote branches
$ git push origin --delete old-feature # delete a remote branch
$ git branch --set-upstream-to=origin/main main # fix "no tracking branch"
git fetch downloads new commits but doesn't touch your working files. git pull is fetch + merge (or --rebase) in one step. When in doubt, fetch first and look before merging.
05 Undoing things
Git rarely deletes anything permanently — but a few commands get close. Know which is which.
| Command | Undoes | Risk |
|---|---|---|
git restore <file> | Uncommitted edits to a file, back to last commit. | Local edits lost |
git restore --staged <file> | Unstages a file; edits are kept. | None |
git reset --soft HEAD~1 | Undoes the last commit; changes stay staged. | Low |
git reset --hard HEAD~1 | Undoes the last commit and all working changes. | High — data loss |
git revert <commit> | Adds a new commit that undoes an old one — safe on shared branches. | None |
git clean -fd | Deletes untracked files and folders. | High — data loss |
reset --hard and clean -fd destroy uncommitted work with no confirmation. Run git status first, and consider git stash instead if you might want those changes back.
StashShelve work-in-progress without committing
$ git stash # shelve tracked changes
$ git stash -u # include untracked files too
$ git stash list
$ git stash pop # reapply the most recent stash and drop it
$ git stash apply stash@{1} # reapply a specific one, keep it in the list
ReflogThe safety net for "I think I lost a commit"
$ git reflog # every place HEAD has pointed, even after reset --hard
$ git reset --hard HEAD@{2} # jump back to a prior state
06 Inspecting history
$ git log --oneline --graph --all # the shape of the whole repo at a glance
$ git log -p -- path/to/file.js # full diff history of one file
$ git diff # working tree vs. last commit
$ git diff --staged # staged changes vs. last commit
$ git show a1b2c3d # everything in one commit
$ git blame path/to/file.js # who last touched each line, and when
$ git bisect start
$ git bisect bad # current commit is broken
$ git bisect good v1.2.0 # this old tag was fine — binary-search the regression
Reading a diff
diff --git a/src/config.js b/src/config.js
@@ -12,7 +12,7 @@ export const settings = {
- timeout: 3000,
+ timeout: 5000,
retries: 3,
};
07 Fork & pull-request workflow
How contributions actually travel on GitHub, whether it's your own team's repo or an open-source project you don't have write access to.
- Fork the repository on GitHub (skip this if you already have write access — branch directly instead).
git clone git@github.com:you/repo.git— clone your fork.git remote add upstream git@github.com:original-owner/repo.git— track the source.git fetch upstream && git rebase upstream/main— start from the latest.- Create a feature branch, commit your work,
git push origin feature/my-change. - Open a pull request on GitHub, targeting the upstream repo's default branch.
- Address review comments with more commits (or an amend + force-push), then it gets merged.
upstream is the original repo, origin is your fork. Rebasing onto upstream/main before opening a PR avoids conflicts caused by staleness rather than real disagreement.
08 GitHub CLI — gh
Everything above the Git layer — issues, PRs, Actions — from the terminal instead of the browser.
$ gh auth login # one-time browser or token auth
$ gh repo clone owner/repo
$ gh repo create my-project --public --source=. --push
$ gh pr create --title "Add search filter" --body "Closes #42"
$ gh pr list --state open
$ gh pr view 42 --web # open it in the browser
$ gh pr checkout 42 # pull someone else's PR branch locally
$ gh pr merge 42 --squash --delete-branch
$ gh issue create --title "Bug: filter resets on refresh"
$ gh issue list --label bug
$ gh workflow list
$ gh run watch # tail the currently running Actions job
$ gh gist create notes.md --public
09 Repo files & conventions
Files GitHub recognizes by name and gives special treatment.
| File | Purpose |
|---|---|
.gitignore | Patterns for files Git should never track (build output, secrets, node_modules/). |
README.md | Rendered on the repo's homepage — what it is, how to run it. |
LICENSE | Legal terms for reuse; GitHub detects and labels common ones automatically. |
CONTRIBUTING.md | Linked automatically when someone opens an issue or PR. |
CODEOWNERS | Maps paths to reviewers; auto-requests review on matching PRs. |
.github/ISSUE_TEMPLATE/ | Structured forms shown when someone opens a new issue. |
.github/PULL_REQUEST_TEMPLATE.md | Pre-fills the PR description box. |
.github/workflows/*.yml | GitHub Actions pipelines — see below. |
10 GitHub Actions, minimally
A workflow file that runs tests on every push and pull request.
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
Commit it under .github/workflows/ and GitHub picks it up automatically — check progress under the repo's Actions tab, or with gh run watch.
11 Commit & PR etiquette
The habits that make a shared history and review queue pleasant to work in.
Commit messagesConventional prefixes
| Prefix | Use for |
|---|---|
feat: | A new feature. |
fix: | A bug fix. |
docs: | Documentation only. |
refactor: | Code change that isn't a fix or a feature. |
test: | Adding or correcting tests. |
chore: | Build, tooling, dependency upkeep. |
Branch names
feature/search-filter
fix/login-redirect-loop
chore/bump-eslint
Opening a PRWhat makes one easy to review
- Small and focused — one concern per PR, not a week of unrelated changes.
- Descriptive title, and
Closes #42in the body to auto-link and close the issue on merge. - Explain why, not just what — the diff already shows what changed.
- Once review has started, prefer new commits over force-pushing so reviewers can see what changed since their last pass.
main accepts a merge, and block direct pushes to it entirely. Set this under the repo's Settings → Branches.
12 Troubleshooting
Errorfatal: not a git repository
You're outside a repo, or above its root. cd into the project, or run git init if it's genuinely new.
ErrorPermission denied (publickey)
GitHub doesn't recognize your SSH key. Confirm it's added under Settings → SSH and GPG keys, then re-test:
$ ssh -T git@github.com
SituationCommitted to the wrong branch
$ git branch rescue-branch # save a pointer to this commit
$ git reset --hard HEAD~1 # remove it from the current branch
$ git switch rescue-branch # continue where you meant to be
SituationStuck in a detached HEAD
You checked out a commit or tag directly instead of a branch. Any new commits here aren't on a branch and can be orphaned. Save them with:
$ git switch -c rescued-work
SituationLocal and remote branches have diverged
$ git pull --rebase # replay your commits on top — usually the cleaner history
# or, to preserve exactly what happened on both sides:
$ git pull # creates a merge commit
SituationPushed a large binary or a secret by accident
Deleting the file in a new commit isn't enough — it's still in history. Use git filter-repo or the BFG Repo-Cleaner to strip it from every commit, force-push, and — for secrets — rotate the credential regardless.
13 Full cheat sheet
Every command above, in one scannable table.
| Command | Description |
|---|---|
git init | Create a new local repository |
git clone <url> | Copy a remote repository locally |
git status | Show staged/unstaged/untracked changes |
git add <file> / -p / . | Stage changes |
git commit -m "…" | Record a snapshot of staged changes |
git commit --amend | Edit the previous commit |
git push / -u origin <branch> | Send commits to the remote |
git pull / --rebase | Fetch + merge (or rebase) remote commits |
git fetch --all --prune | Update remote refs without merging |
git branch / -d / -D | List / delete a branch |
git switch <branch> / -c | Change branch / create and change |
git merge <branch> | Combine another branch into this one |
git rebase <branch> / -i | Replay commits on a new base / edit interactively |
git cherry-pick <sha> | Apply one specific commit here |
git restore / --staged | Discard working changes / unstage |
git reset --soft/--hard | Move HEAD, keeping or discarding changes |
git revert <sha> | Undo a commit with a new, safe commit |
git stash / pop / list | Shelve and restore work-in-progress |
git reflog | History of every HEAD movement — the ultimate undo |
git log --oneline --graph | Visualize commit history |
git diff / --staged | Show unstaged / staged changes |
git blame <file> | Show who last changed each line |
git bisect | Binary-search history for a regression |
gh pr create / list / merge | Manage pull requests from the terminal |
gh issue create / list | Manage issues from the terminal |
gh run watch | Tail a running Actions workflow |