git started
1 Your own repo
Make a folder, turn it into a repo
ls -a to see .git. That folder is
the repo.
Write something, look at it through git
Says untracked. Git sees it but is not watching it yet.
Stage it, commit it
Do this twice more with different edits before moving on.
Log in to GitHub
GitHub.com → HTTPS → Yes to authenticate git → browser. That "Yes" is what stops password prompts later.
Push it to GitHub
| Flag | Answers |
|---|---|
--source=. | this folder (omit for an empty repo) |
--public | who sees it (--private otherwise) |
--push | upload now (omit to push later) |
--remote=origin | the short name you push to |
--description | what it is |
Flags go in any order. Only the repo name is positional.
See what got wired up
Bare git push works because --push set the
upstream. Without it: git push -u origin main once.
2 Fork, branch, PR
Try it the obvious way. It fails.
Permission denied. You got read, not write, so your work
is stuck on your laptop. Now cd .. and delete that folder, or you will
spend ten minutes typing into the wrong one.
Fork and clone in one
Fork is GitHub's File → Make a Copy. Must show
your username on origin, and accelerate-muj
on upstream.
If you forked with the web button instead
A remote is a long URL saved under a short name, like
Mom in your phone. origin = your fork, you can push.
upstream = ours, fetch only.
Sync, then branch
"Already up to date" is a fine answer. The * in
git branch confirms where you are. Modern equivalent:
git switch -c add-{{user}}.
Make your file, then sign it
Filename must be your GitHub username. Open it, write your version of
Sonnet 18 — modern English, Hindi, a parody, anything — and end it with
Written by {{name}}.
phase-2/sonnet-18.md or edit anything else. One file per
username is what stops thirty pull requests colliding. Shared files are Phase 3.Look at what changed
The first git diff shows nothing. It only watches
files git already tracks, and yours is brand new. After git add every
line appears with a +, and + means addition.
Commit, then push to your fork
-u links this branch to that remote branch once, so from
then on bare git push works. git add . needs the space;
git add. fails.
Open the PR
| Flag | Answers |
|---|---|
--title | the line shown in the PR list |
--body | the description under it |
--fill | use my last commit message for both |
--draft | unfinished, cannot merge yet |
--reviewer | ask a specific person to look |
--web | fill the form in a browser instead |
--repo | force the destination if gh guesses wrong |
Because upstream is set, gh already knows the
repo, the source branch and the destination. gh pr create --fill is the
shortest version that works.
After it merges
3 Teams and conflicts
Create the team repo
A template is not a fork. You get the files with a fresh history, one commit, and no link back to the original — what you want when starting from a skeleton rather than contributing to someone's project.
Pick a leader who owns the repo and merges the PRs. Not the best programmer in the group; it is an administrative job, and it is what maintainers of every open source project do all day.
Add each teammate
Start early, invites take time. Or Settings → Collaborators → Add people.
Accept the invite
Note the id, then:
gh repo accept is not a command
It does not exist. Use the two above, or click the link on
github.com/notifications.
Until you accept, your push is rejected with a confusing permission error.Clone and branch
No fork and no upstream this time. You push to
origin directly because you are inside the project. That is the
difference between working with colleagues and contributing as a stranger.
Edit the shared file
Open team-sonnet.md and do two things:
- Rewrite your assigned line of the sonnet. The leader hands out line numbers, or call them out around the table.
- Add your username to the Credits block at the bottom, on the line directly under the comment.
Commit, push, open the PR
No --repo now. Same repo, branch → main.
When GitHub says your branch has conflicts
Nothing has broken. The first PR merged cleanly and yours was built on
a main that no longer exists. Somebody's name is sitting where you put
yours, and git will not guess which of you should win.
Resolve it
Three parts. Above ======= is what is already on
main; below it is what you are adding. The markers are plain text git
inserted, nothing is watching them.
git add is how you say resolved. There is no
separate resolve command, which surprises everybody. Panicking?
git merge --abort puts everything back.
Review and merge each other
To send it back instead:
gh pr review PR-NUMBER --request-changes --body "Line 7 does not scan"
main and fixes their conflict.
Five at once and nobody can untangle it. Notice what merging keeps doing to your
teammates — merge order is a decision with consequences for other people, and
that is most of the job.If you have time: rebase instead of merge
Merge keeps your branch as it happened and adds a
joining commit; honest, and the graph tangles. Rebase replays your
commits on top of the new main so history reads as one line. New commits,
new hashes, which is why the push needs forcing. The rule most teams settle on:
rebase your own unmerged branch, merge shared branches.
--force-with-lease, never plain --force
They look interchangeable. --force overwrites the remote branch whatever
is on it, so if a teammate pushed while you were resolving, you have silently
destroyed their commit. --force-with-lease checks the remote is still
where you last saw it and refuses if anyone touched it.If you have time: branch protection
Now nobody can push straight to main, including the
leader.
<<<<<<<, ======= and
>>>>>>> separate? Which command marks a conflict
resolved? Why was your push rejected after a rebase? What does
--force-with-lease check that --force does not? Your
teammate merged first and your branch is stale — merge or rebase?
Help
| What you see | Fix |
|---|---|
Permission denied on push, Phase 2 |
You cloned ours, not your fork:git remote set-url origin https://github.com/{{user}}/git-started.git |
Permission denied on push, Phase 3 |
Invite not accepted:gh api user/repository_invitations
then gh api -X PATCH user/repository_invitations/ID |
'add.' is not a git command |
git add . with a space |
unknown command "accept" for "gh repo" |
It does not exist. Use the invitations API, or accept in the browser. |
fatal: not a git repository |
cd into the project folder. pwd shows where you are. |
error: pathspec did not match |
Missing -c: git switch -c <branch> makes a new
one, without it git looks for an existing one |
git diff shows nothing, Phase 2 |
Correct. It only watches tracked files and yours is new.
git add . then git diff --staged |
| PR opened against your own fork | gh guessed wrong. Force it:
--repo accelerate-muj/git-started |
remote upstream already exists |
Harmless. Ignore it. |
! [rejected] main -> main |
git pull origin main then push again |
CONFLICT (content): Merge conflict in ... |
Expected in Phase 3. Keep both, delete markers, git add ., commit. |
Leftover <<<<<<< in the file |
Search for <<< and delete every marker line |
refusing to merge unrelated histories |
git pull origin main --allow-unrelated-histories |
| "There isn't anything to compare" | You committed to main. Branch and push that instead. |
gh pr merge fails |
PR still has conflicts. Author fixes first. |
| Password asked for and rejected | gh auth login, say yes to the git credentials question |
gh: command not found |
Close the terminal, open a new one |
| Stuck in an editor you cannot exit | It is vim. Esc then :wq then Enter. |
| Want to undo and start again | git merge --abort. Nothing is lost. |
Nothing matches? Run git status.
It cannot break anything and it tells you where you are. Then put your hand up.
Phase 4 and onwards
The other twelve
| 5 | Rewriting history | Interactive rebase, squashing, splitting a commit. |
| 6 | Forensics | bisect finding what broke the build while you make tea. |
| 7 | Merging deeply | What today's conflict actually was. |
| 8 | Remotes, big repos | Refspecs, worktrees, submodules, LFS. |
| 9 | Plumbing | Inside .git. The one where it clicks. |
| 10 | Trust | Anyone can commit under your name. Signing. |
| 11 | Config, automation | Aliases, attributes, hooks. |
| 12 | GitHub as a platform | Everything that is not git. |
| 13 | gh CLI in full | The whole surface, plus gh api. |
| 14 | Actions and CI/CD | Making the repo do the work. |
| 15 | Being a maintainer | Reviewing, triage, saying no, burnout. |
| 16 | Scale and origins | Ten days in 2005, and why git is shaped like this. |