From zero to your first pull request.
Run these now. Raise a hand if anything errors.
git --version # is Git installed? java -version # JDK 17 or newer javac -version # compiler, not just Java git config --global user.name "Your Name" # whose name is on commits git config --global user.email "you@example.com" # match your GitHub login git config --global init.defaultBranch main # name the first branch main git config --global core.editor "code --wait" # if you use VS Code
The email should match your GitHub account.
Git is a save-point system for your work — and the only sane way for several people to write on the same project without overwriting each other.
git status tells you where everything currently sits. Run it after every command today.
Just something to practice on — a tiny buko juice ordering app that runs in the terminal. Plain Java — no Maven, no Gradle, nothing to install beyond a JDK.
booko/
└── src/
├── Main.java # menu loop
├── Drink.java
└── BookingService.java
├── team.md # you'll add your name here
├── ISSUES.md # mirrors the GitHub issues
└── .gitignore
Run it:
javac -d out src/*.java # compile every .java into out/ java -cp out Main # run the Main class from out/
You can't push to a repo you don't own — that's why open source runs on forks. Fork JanDexter/booko, unchecking "Copy the main branch only".
git clone https://github.com/<your-username>/booko.git # get your own copy cd booko # go into it git remote -v # origin = your fork git log --oneline # the history so far
Open team.md, add your name and your favorite place in Davao. Then:
git status # look at this output git diff # the exact lines you changed git add team.md # stage it for the next commit git status # now look again — what moved? git commit -m "Add <name> to team list" # save it, with a message
Finish this sentence: "This commit will…"
Imperative mood, under ~50 characters, one logical change per commit.
A branch is just a movable label pointing at a commit. Creating one is instant and costs nothing.
main A───B───C
\
feat/quantity D───E # your work, isolated
The rule: main always works. All new work happens on a branch.
git branch # where am I? git switch -c feat/my-thing # create and move git switch main # go back
Pick an issue from the list, then:
git switch main # back to the trunk git pull # get the latest git switch -c feat/<short-name> # -c creates it, then moves you # edit your files, save git add . # stage everything you changed git commit -m "<what you changed>" # save it, with a message git push -u origin feat/<short-name> # upload it, first time only
-u is only needed on the first push. After that, plain git push.
GitHub will not accept your account password from the terminal. Your first push has to sign you in — don't type a password, let the browser do it.
gh auth login first, pick HTTPS, authenticate in the browserStuck? Raise a hand — it's faster than the fallback (Settings → Developer settings → tokens (classic), tick repo, paste as password).
An issue is a to-do item that lives in the repo instead of in someone's head. That's all it is.
Six open issues, all labeled good first issue. Pick any — you're each on your own fork, so duplicates are fine.
JanDexter/booko — you're proposing into the originalA PR is a proposal, not a delivery. It's the conversation before code reaches main — and we'll merge one of yours on screen.
A conflict happens when two branches change the same lines of the same file. Git refuses to guess which one you meant.
Top is yours, bottom is theirs. These are plain text. Delete the markers, keep the version the file should end up with, save.
git switch feat/<short-name> # back onto your branch git fetch origin # download, do not merge yet git merge origin/promo-banner # this WILL conflict
Open src/Main.java, resolve the markers, then:
git add src/Main.java # marks the conflict resolved git commit # message is pre-filled, just save git push # send it up
No promo-banner? You forked main-only. Run git remote add upstream https://github.com/JanDexter/booko.git, then merge upstream/promo-banner instead.
A conflict is not an error. If you panic: git merge --abort puts everything back.
Your PR is a proposal to a repo you don't own, so it lands when the maintainer says so. The fork, though, is yours — merge it there yourself.
git switch main # your fork's main git merge feat/<short-name> # fast-forward, nothing to resolve git push # your repo, your merge
Two things with your name on them: a branch you merged, and an open PR proposing the same work to someone else's project.
| Throw away edits to a file | git restore <file> |
| Unstage something you added | git restore --staged <file> |
| Fix the last commit message | git commit --amend |
| Undo a commit already pushed | git revert <hash> |
| Bail out of a merge | git merge --abort |
| See what you did | git log --oneline --graph |
Some things must never reach a repo. List them once and Git stops seeing them.
out/ *.class # compiled output, never commit this .env # API keys, passwords — the big one *.log .DS_Store .idea/
A secret pushed once is a secret leaked forever. Rotating the key is the only real fix — deleting the commit is not enough.
| git clone <url> | copy a repo onto your machine |
| git remote -v | which GitHub repos you're wired to |
| git status | what changed, and what's staged |
| git diff | the exact lines you changed |
| git add <file> | stage it for the next commit |
| git commit -m "…" | save what's staged, with a message |
| git switch -c <name> | create a branch and move onto it |
| git pull | download the latest and merge it in |
| git push -u origin <name> | upload your branch the first time |
| git merge <branch> | join another branch into yours |
git switch main && git pull # start from the latest # on a fork: git pull upstream main git switch -c feat/thing # branch # ... work ... git add . # stage git commit -m "Do the thing (closes #3)" git push -u origin feat/thing # push # open a PR, get it reviewed, merge
That's 90% of professional Git. Everything else is a lookup.
Fork → branch → PR → review is what every open-source project runs on. You just did it end to end.
label:"good first issue"Questions → open an issue on the workshop repo.