4. Working with GitHub¶
Beginner → Intermediate · 14 min read
Git works entirely on your machine. GitHub is a hosting service for Git repositories, plus everything a team needs around them: pull requests, code review, issues, CI with Actions, releases. Your laptop and GitHub each hold a full copy of the repository, and you sync them with push and fetch.
To show real output, the "GitHub" on this page is a local bare repository standing in for
github.com/asha-rao/chat-app, with two developers, Asha and Ravi, each with their own clone. The commands are
identical against real GitHub.
4.1 Authenticate once¶
GitHub doesn't accept your account password for Git. Pick one of these:
The GitHub CLI stores a token and configures Git to use it. You'll want gh
anyway for pull requests (4.6).
ssh-keygen -t ed25519 -C "asha@example.com" # press Enter to accept the default path
cat ~/.ssh/id_ed25519.pub # paste into GitHub → Settings → SSH and GPG keys
ssh -T git@github.com # "Hi asha-rao! You've successfully authenticated"
Then use git@github.com:asha-rao/chat-app.git URLs instead of https://....
GitHub → Settings → Developer settings → Fine-grained tokens, scoped to the repositories you need. Paste it when Git asks for a password; Git Credential Manager (installed with Git for Windows) remembers it.
4.2 Push an existing project¶
Create an empty repository on GitHub (gh repo create chat-app --private --source=. --push does it all in one
command), or connect an existing one:
git remote add origin https://github.com/asha-rao/chat-app.git
git remote -v
git push -u origin main
git status -sb
origin https://github.com/asha-rao/chat-app.git (fetch)
origin https://github.com/asha-rao/chat-app.git (push)
branch 'main' set up to track 'origin/main'.
To https://github.com/asha-rao/chat-app.git
* [new branch] main -> main
## main...origin/main
originis just the conventional name for "the remote I cloned from / push to". A repo can have several.-u(upstream) links your localmaintoorigin/main, so later a plaingit pushandgit pullknow where to go, andgit statuscan tell you if you're ahead or behind.origin/mainis a remote-tracking branch: your local, read-only bookmark of wheremainwas on GitHub the last time you talked to it.
4.3 Clone¶
Ravi gets his own full copy, history included:
Clone sets up origin and the tracking branch automatically. For big repositories,
git clone --depth 1 fetches only the latest snapshot (fine for CI and quick experiments).
4.4 Fetch vs pull, and the rejected push¶
Ravi pushes a commit. Meanwhile Asha commits a README and tries to push:
To https://github.com/asha-rao/chat-app.git
! [rejected] main -> main (fetch first)
error: failed to push some refs to 'https://github.com/asha-rao/chat-app.git'
hint: Updates were rejected because the remote contains work that you do not
hint: have locally. This is usually caused by another repository pushing to
hint: the same ref. If you want to integrate the remote changes, use
hint: 'git pull' before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
GitHub refuses because accepting Asha's push would throw away Ravi's commit. First, look before you leap:
git fetch # download new commits; changes nothing in your files or branches
git status -sb
git log --oneline --graph --all
From https://github.com/asha-rao/chat-app
620a8dc..8c90f6a main -> origin/main
## main...origin/main [ahead 1, behind 1]
* b267a28 Add README
| * 8c90f6a Add temperature
|/
* 620a8dc Add app
"Ahead 1, behind 1": the histories have diverged. Now integrate Ravi's commit. pull is fetch + merge (or
rebase); with --rebase Asha's local commit is replayed on top of Ravi's, keeping history linear:
Successfully rebased and updated refs/heads/main.
* 6a566ee Add README
* 8c90f6a Add temperature
* 620a8dc Add app
To https://github.com/asha-rao/chat-app.git
8c90f6a..6a566ee main -> main
| Command | Downloads | Changes your branch | Use it when |
|---|---|---|---|
git fetch |
Yes | No | You want to see what changed first |
git pull |
Yes | Yes: merges, creating merge commits on divergence | Your team prefers merge commits |
git pull --rebase |
Yes | Yes: replays your local commits on top | Most of the time (set pull.rebase true) |
Rebasing here is safe: the commits being replayed are your own, not yet pushed (the golden rule from page 2).
4.5 Forks and upstream¶
For open-source projects (or repositories you can't push to), you fork: GitHub copies the repository to your account. You push to your fork and open a pull request back to the original.
gh repo fork some-org/rag-toolkit --clone # fork on GitHub and clone your fork
git remote -v # origin = your fork, upstream = the original
git fetch upstream
git switch -c fix/typo-in-docs upstream/main # branch from the latest original
# ...fix, commit...
git push -u origin fix/typo-in-docs
gh pr create --repo some-org/rag-toolkit
Keep the fork's main branch in sync with git fetch upstream and git rebase upstream/main (or the "Sync fork"
button on GitHub).
4.6 Pull requests from the terminal¶
A pull request (PR) asks to merge one branch into another, with a place for review, discussion and CI checks.
The daily loop with gh:
git switch -c feature/streaming
# ...commit work...
git push -u origin feature/streaming
gh pr create --fill # title and body from your commits; --draft for work in progress
gh pr checks --watch # wait for CI
gh pr view --web # open it in the browser
gh pr checkout 42 # review someone else's PR locally
gh pr review 42 --approve # or --request-changes -b "..."
gh pr merge 42 --squash --delete-branch
Good PRs are small (under ~400 changed lines), do one thing, and explain why in the description, plus how to test it. For AI projects, include example prompts and outputs or eval scores before and after.
4.7 What else GitHub gives you¶
| Feature | What it's for in a GenAI project |
|---|---|
| Issues and Projects | Track bugs, prompt regressions and experiments |
| Actions | CI: lint, tests and evals on every PR; deployments (page 6) |
| Secrets (repo / environment) | API keys for CI, never in the code |
| Push protection & secret scanning | Blocks pushes containing known key formats (OpenAI, Anthropic, AWS…) |
| Dependabot | PRs that update vulnerable dependencies |
| Releases | Tagged versions with notes and build artifacts |
| Pages | Free hosting for docs and static sites |
| Codespaces | A cloud dev environment from the repo's devcontainer |
Interview questions¶
What's the difference between git fetch and git pull?
fetch downloads new commits and updates remote-tracking branches like origin/main without touching your
working tree or local branches. pull is fetch followed by integrating origin/main into your branch, by
merge or (with --rebase) by replaying your local commits on top.
Your push was rejected with 'fetch first'. What happened and what do you do?
Someone pushed commits you don't have, so your push would overwrite them. Fetch, look at what changed, then
integrate with git pull --rebase (or merge), resolve any conflicts, run the tests and push again. Don't
force-push to a shared branch.
What is origin/main?
A remote-tracking branch: your local, read-only record of where main was on the origin remote at the last
fetch. git status compares your branch to it to report ahead/behind, and it only updates when you fetch, pull
or push.
Fork vs clone vs branch?
A clone is a full local copy of a repository. A branch is a line of work inside one repository. A fork is a server-side copy of someone else's repository under your account, used when you can't push to the original; you push to your fork and open a pull request upstream.
Practice¶
- Create a private repository with
gh repo create, push a project and open a PR from a branch. - Simulate two developers with two clones in different folders and reproduce the rejected push.
- Fork an open-source GenAI project, fix a typo in its docs and open a pull request.
Next: 5. Team workflows Back to: Git & GitHub overview · Notes overview