A hands-on team demo: branches · pull requests · code review · merge conflicts
2026-07-07
We’ll move between these slides and live coding.
By the end you’ll have practiced these actions:
Every interactive slide tells you who acts and where.
Who:
Where:
Several tools, one workflow. Most people use Positron or RStudio; every git step can also be done from the terminal. We show the options where they differ.
main with a ruleset WATCHmain EVERYONEmainWatch setup. You’ll feel it later when a direct push to main is refused.
WATCH github.com Settings → Rules → Rulesets
Repo: Settings → Rules → Rulesets → New ruleset → New branch ruleset.
protect-mainActiveDefault (or pattern ~DEFAULT_BRANCH)emLab recommends protecting main — it’s not strictly required, but it’s best practice and we’ll use it today.
Everyone gets a local copy of the shared repo and links it to GitHub.
EVERYONE github.com
Navigate to our shared repo:
github.com/emlab-ucsb/sop-demo
Click the green Code button:
Copy the URL with the copy icon.
# HTTPS
https://github.com/emlab-ucsb/sop-demo.git
# SSH
git@github.com:emlab-ucsb/sop-demo.git
EVERYONE Positron / RStudio / Terminal
Positron/VS Code
File → New Folder from Git…
Paste the URL, pick a destination (e.g. ~/github/), click OK.
RStudio
File → New Project… → Version Control → Git
Paste the URL, choose where to store it, Create Project.
Store repos in a dedicated folder like ~/github/. Avoid cloud-synced folders (Google Drive, iCloud, Dropbox) — they cause Git sync conflicts.
mainEVERYONE Positron / RStudio / Terminal
Make a small change directly on main, commit it, and try to push — it should be refused.
The push is rejected:
remote: error: GH013: Repository rule violations found for refs/heads/main.
That’s the protection working. Nothing reaches main without a PR.
Undo the test commit — it’s only on your machine (the push failed). Reset your local main to match GitHub:
git reset --hard origin/mainCmd+Shift+P → Git: Undo Last Commit, then Discard Changes on the file in the Source Control panel.Formatting with Air (R) is an emLab standard. Set it up once. We’ll see it work in Section 5.
EVERYONE Positron / VS Code
Cmd+Shift+X) → search “Air” (by Posit) → Install.Cmd+Shift+P → Open User Settings (JSON)) and add:Note: You can enable or disable Air per-workspace, and turn formatting off later by setting "editor.formatOnSave": false. Useful when editing an unformatted file, to avoid a whole-file diff.
We’ll watch Air reformat code on save when we make our first change in Section 5 — no need to test it now.
EVERYONE RStudio
Air isn’t tightly integrated with RStudio. Use the styler package instead:
Then Addins → Style active file before each commit, and enable Tools → Global Options → Code → Saving → Ensure source files end with a newline.
Issues track work alongside the code. We’ll create one, then branch directly from it so the branch and PR are linked to the issue.
EVERYONE github.com Issues → New issue
Create an issue for the small task you’ll do today:
Title: “Add [name]’s greeting function”
Body: what & why, plus a checklist:
Sidebar: set an Assignee (yourself), a Label (enhancement), and optionally a Milestone.
EVERYONE github.com → Positron / RStudio / Terminal
On your issue, in the Development section (right sidebar) → Create a branch. Keep or change the suggested name — either way the branch is linked to the issue.
Now get that branch onto your machine:
Creating the branch from the issue links them: branch activity shows in the issue timeline, and the issue will close automatically when the PR merges.
Make a small change on your branch, commit it, and push it to GitHub.
EVERYONE Positron / RStudio
Create a new file named after you so we don’t overlap — e.g. team/yourname.R:
Type it messily first (no spaces, odd indents), then save and watch Air reformat it to Tidyverse style.
Working in your own file avoids accidental conflicts. We’ll create a conflict on purpose later in a shared file to demonstrate how to resolve it.
EVERYONE Positron / RStudio (or Terminal)
In Source Control panel (Positron/VS Code) or Git pane (RStudio):
team/yourname.R (click the + next to the file).Write messages your future self can read. Source: xkcd.com/1296
Prefer the terminal?
EVERYONE Positron / RStudio (or Terminal)
Prefer the terminal?
You can create a branch from:
git switch -c your-branch.The difference: a branch made on GitHub already exists remotely, so you just push / sync. A branch made locally (IDE or terminal) needs a first Publish Branch / git push -u to create it on GitHub.
Propose your branch for merging into main and ask your partner to review it.
EVERYONE github.com
After pushing, GitHub shows a “Compare & pull request” banner — click it (or Pull requests → New pull request).
main · Compare: your branchCloses #<issue-number>.Branching from the issue links the two. In most cases, closing a PR linked to an issue will also close the issue when the PR merges by default. You can also use the Closes #N or Fixes #N keywords to do so. One PR can close several issues: Closes #12, closes #15.
Press Create pull request. The PR is now open for review.
EVERYONE github.com
Pair up: A reviews B, and B reviews A.
In your PR’s right sidebar → Reviewers → choose your partner. Our ruleset requires 1 approval before the PR can merge, so your partner’s review is what unblocks the merge.
(Optional: Assignees marks who owns/will merge the PR — you can assign yourself. The important one today is Reviewer = your partner.)
Concept — applies to every review
GitHub gives three review outcomes:
Good review habits (from the emLab Code Review SOP):
Reviewer requests changes → author revises → reviewer approves → merge → delete branch.
EVERYONE (as reviewer) github.com
Open your partner’s PR → Files changed tab.
“Request changes” blocks the merge until you re-review — use it when you want another look before it can merge.
Good to know — Positron / VS Code / RStudio
Switch to the PR branch locally and run the code — often the only way to catch real errors.
Positron / VS Code’s GitHub Pull Requests extension even lets you check out a PR, comment, and approve without leaving the editor.
EVERYONE (as reviewer) github.com
Re-open your partner’s PR and look at the new commits in Files changed.
For a tiny fix, you can also just make the change yourself:
When the changes look good: Review changes → Approve → Submit.
Talk with your team about when reviewers should edit directly. For anything substantial, leave a comment so the author makes the change and keeps ownership.
EVERYONE (as author) github.com
Once approved, the green Merge pull request is enabled.
Choose a merge strategy from the dropdown menu → click Merge pull request → Confirm merge.
Three merge strategies (the dropdown on the merge button):
main; tidy history, handy for messy or exploratory branches.main with no merge commit; linear history.Because your PR said Closes #N, merging it auto-closes your issue — check the Issues tab to confirm.
EVERYONE github.com (+ IDE)
Right after merging, GitHub shows Delete branch — click it. This deletes the branch on GitHub (the remote copy).
Now clean up on your machine:
main and pull — Positron/VS Code/RStudio: pick main in the branch picker, click pull/sync. This brings the merged work down.Cmd+Shift+P → Git: Delete Branch… → pick it.git branch -d <your-branch>There are always two copies of a branch — remote (GitHub) and local (your machine). Deleting one doesn’t delete the other.
Communication is the most important code review tool. On your project team, agree on the code review conventions up front.
No single right answer — what matters is the team decides and writes it down (in a README.md or similar).
Two changes to the same line can’t auto-merge. Let’s create one on purpose, then resolve it using the IDE and github.com.
EVERYONE (in your pairs) github.com
A conflict happens when multiple people change the same line. You’ll create one on purpose with your partner a shared file (e.g. sop-demo/conflict-files/partners-1.R).
It will take three steps:
main.main.First, each pair will be assigned to a file in the conflict-files folder.
Next, decide who is Partner A and who is Partner B.
mainEVERYONE (in your pairs) Positron / RStudio
Both partners: Make sure main is up to date first:
main in the branch picker → pull / sync.git switch main && git pull.Both partners: Create your own branch from the main (A and B on separate branches).
EVERYONE (in your pairs) Positron → github.com
Partner A edits their assigned file. Partner B should not edit it yet, but prepare for Partner A’s PR.:
main.Partner B, within their branch:
EVERYONE github.com
Click Resolve conflicts to open the web editor:
Options:
<<<<<<<, =======, >>>>>>> markers, keeping the correct line.Mark as resolved → Commit merge. The PR is now mergeable.
GitHub labels the sides with the branch names (top = your branch, bottom = main).
Alternative — Positron / VS Code
After Git: Merge Branch…, the conflicted file opens in the merge editor:
main.Then save, stage, commit, push.
Image: Posit Positron docs
Alternative — RStudio
RStudio has no merge editor — the conflicted file just shows the raw markers. Edit them by hand, then stage and commit in the Git pane.
Image: NCEAS coreR
The top (HEAD) is your branch; the bottom is the incoming version. Delete the <<<<<<< / ======= / >>>>>>> lines and whichever version you don’t want.
More on conflicts in RStudio: NCEAS coreR — Collaborating with Git
mainEVERYONE — do this regularly, not just when there’s a conflict
Pull main into your branch often — the longer it drifts, the harder the merge.
Watch out: Pull / Sync only updates your current branch — it does not pull in main’s new commits. For that you must merge main in.
How (with main already pulled):
Cmd+Shift+P → Git: Merge Branch… → pick main.git switch your-branch, then git merge main.Also: small, focused branches and PRs, and coordinate on shared files.
main with a ruleset (PR + 1 review)This is the everyday emLab workflow: code reaches main through branch-based tasks, pull requests, and review.
The full emLab Standard Operating Procedures cover all of this in depth:
Git & GitHub demo