T19-L02 · Share & review code · Level 2 Power user · 15-minute read, plus 75 minutes of doing

Almost what you need

Mia's qPCR protocol now lives in Gitea, with every change kept (T19-L01 · Keep Your Files in Gitea and Get Any Version Back). Two things are missing. She wants to work on the files on her own computer with OpenCode, not only in the browser. And her colleague Jonas should be able to change the protocol too, without files going back and forth by email.

In this book you connect your computer to Gitea, copy the repository down, change it with OpenCode, send the change up, bring a colleague's change down, and settle the one situation where a person has to decide: both of you changed the same line. You are at Level 2 Power user: from now on your mistakes reach Jonas.

After this you can

  • Connect your computer to Gitea with an SSH key, without a password or key ever going through the chat.
  • Copy a repository to your computer with OpenCode, and keep raw data out of it with a .gitignore file.
  • Commit and push your changes, and pull a colleague's changes.
  • Stop OpenCode from settling a conflict on its own, and decide yourself whose line stays.
  • Give a colleague write access to your repository.

Before you start

Last verified 25 September 2026. Everything here works on any Gitea, including gitea.com, and needs no paid plan. OpenCode Desktop 2.0.16 does the Git work; you type no commands. Details for experts at the end of this book.

The idea in one page

  • There are now two copies. One on Gitea, one on your computer. A commit saves a version on your computer. A push sends your commits to Gitea. A pull brings your colleagues' commits down.
  • An SSH key is a pair. The public half is like a padlock: you hand it to Gitea. The private half is the only key that opens it and never leaves your computer.
  • Nothing secret goes into the chat. What you type, and the files OpenCode reads, go to the model provider. Paste only the public key into Gitea, never a password, token or private key into a message.
  • .gitignore is a list of files Git never takes, such as raw data and password files.
  • Pull before you push. If you and a colleague changed the same line, Git can't choose, and neither should OpenCode: a person decides.

Watch it once (3 minutes)

No sound. A yellow dot points at each button while the caption explains it; OpenCode's answers are real and not sped up. Read the tour as text (opens in a new tab).

Set up (steps 1 to 5, once per computer)

Step 1: Create an SSH key. Open your OpenCode workbench session, check the mode says Build, and send (with the email of your Gitea account):

Create an SSH key so this computer can talk to our Gitea. Use the type ed25519 in the standard place in my home folder (.ssh/id_ed25519), with <your email> as the comment and no passphrase. If a key already exists there, don't replace it.
Never open or show the private key file. Show me only the public key: the one line in the .pub file.

OpenCode answering with one line that starts with ssh-ed25519, a long code, and ends with mia@example.org

You should see: one line starting ssh-ed25519 and ending with your email. Copy it. If OpenCode says a key already exists, that's fine: use its line.

Step 2: Give Gitea the public key. In Gitea, click your picture at the top right, then Settings, then SSH / GPG Keys. Click Add Key next to Manage SSH Keys. Key Name: Laptop. Content: paste the line. Click Add Key.

Gitea's SSH key form: Key Name Laptop, and the Content box holding the ssh-ed25519 line

You should see: the green message The SSH key "Laptop" has been added.

The SSH keys list with the new key Laptop and its fingerprint, added today

Step 3: Copy the repository's SSH address. Open your repository, click Code (the blue button), choose SSH, and click the copy icon next to the address.

The Code menu of the repository with the tab SSH selected and the address ssh://git@localhost:2222/mia/qpcr-protocol.git with a copy button

You should see: an address that starts ssh://git@ or git@. In the pictures it's a test server on this computer; yours shows your organisation's Gitea name.

Step 4: Copy the repository to your computer. Back in the workbench session, send. Replace the address with the one you copied, the name with your full name, and the email with the one under Gitea → Settings → Account:

Copy our repository from Gitea into this folder: <the SSH address>
It's the first connection to this server, so accept its host key once (StrictHostKeyChecking=accept-new).
Keep the line endings exactly as they are on Gitea (core.autocrlf false for this repository, also during the copy).
Then, for this repository only, set my Git name to <your name> and my email to <your Gitea email>.
Don't change any files. Tell me the folder name and the last commit.

OpenCode's answer: Folder qpcr-protocol, and the last commit Revert: keep the Cq spread at 0.3, 0.5 lets bad triplicates through

You should see: the folder name and the last commit you made in T19-L01. The line-endings line matters on Windows; What goes wrong explains it.

Step 5: Open it as its own project. The new folder is inside your OpenCode workbench folder. Add it with the folder-and-plus icon next to Projects, as in T08-L01. Click it, then New session.

A new session for qpcr-protocol: under the message box the project name, Local, and a branch label main

You should see: the branch label main under the message box. The copy came with Git, so OpenCode's Undo works here from the start.

Worked example: Mia and Jonas share the protocol

Structure it

Step 6: Say what you want in one sentence.

When I change the protocol on my computer, I want Jonas to see it on Gitea with my reason, and his changes on my computer, instead of emailing files.

Understand it

Step 7: Know which copy each word moves.

You ask OpenCode to…What happensWho sees it
change a fileOnly the file on your computer changesOnly you
commitA version is saved on your computerOnly you
pushYour commits go to GiteaEveryone with access
pullGitea's newer commits come to your computerYou

Choose tools

OpenCode in Build for everything on Mia's computer, Gitea in the browser for access rights and for Jonas.

Build it: your first change from your computer

Step 8: Keep raw data out. In the qpcr-protocol session, send:

Create a file .gitignore in this project so that these never go into Git: Excel files (*.xlsx, results that may hold unpublished data), anything in a folder raw-data/ (instrument exports), and files named .env (passwords).
Put a one-line comment above each rule that says why. Don't change any other file.

OpenCode's answer: created .gitignore with commented rules for *.xlsx, raw-data/ and .env; no other files changed

You should see: Created .gitignore with the three rules.

Step 9: Make a change and check it. Send:

In protocol.md, add a section "## Plate layout" at the end with two bullet points:
- Use plate-layout.csv: no-template controls in row A, samples in rows B and C.
- Triplicates sit side by side in columns 1 to 3.
Change nothing else.

Then open the Review panel (the rightmost of the three icons at the top right of the session, or Ctrl+Shift+R) and click protocol.md.

The Review panel: Files Changed 2, .gitignore marked A for added and protocol.md with +5 -0; on the right, the five new lines in green under Checks

You should see: Files Changed 2, protocol.md with +5 −0 and only the new section in green. If the whole file shows red and green, see What goes wrong.

Step 10: Commit and push. Close the Review panel, so the answer has room, and send:

Save both changes as one commit with the message "Add the plate layout section and keep raw data out of Git". Then get the latest changes from Gitea (merge, don't rebase) and push.
If Git reports a conflict, stop: don't resolve it yourself. Show me both versions of the lines and who wrote each.

OpenCode's answer: committed and pushed both changes; pulled from Gitea with merge, repository already up to date; no conflicts occurred; pushed main to origin/main

You should see: the commit, No conflicts occurred and Pushed main. Use the last two lines of this request every time you push; step 15 shows why.

Step 11: Check on Gitea. Open the repository and click Commits (with the number, above the file list).

Gitea's commit list with the newest commit Add the plate layout section and keep raw data out of Git by mia, above the revert from T19-L01

You should see: your commit at the top. Gitea shows your account because the email from step 4 matches it.

Build it: work together

Step 12: Give Jonas access. In the repository, click Settings, then Collaborators. Type jonas into Search users…, choose him and click Add Collaborator.

The Collaborators page with the message The collaborator has been added and jonas listed with the access level Write

You should see: jonas with Write: he can change files but not the repository's settings.

Step 13: Jonas changes a line on Gitea. Jonas signs in (or you, as the second account in a private window), edits protocol.md in the browser as in T19-L01 step 7, and commits with a reason.

Jonas's editor with Preview Changes: the master mix line in red and the same line with ROX added in green, and his message Use master mix with ROX: our cycler needs the reference dye

You should see: his commit at the top of Gitea's Commits list, under jonas.

Step 14: Bring his change down. In OpenCode, send:

Get the latest changes from Gitea. Tell me which commits came in, who made them, and what each one changed.

OpenCode's answer: one commit came in, by jonas, with his message, and the master mix line before and after; no conflicts

You should see: Jonas's commit, his message, and the line before and after. Fast-forward means his commit simply came on top; nothing had to be combined.

Build it: when you both changed the same line

Step 15: Push a change that collides. As Jonas, change line 3 of the cycling steps on Gitea to Melt curve from 60 to 95 °C, with the message Start the melt curve at 60 °C to catch primer dimers. Mia hasn't pulled since. In OpenCode she asks to end the curve at 90 °C, with the same last two lines as in step 10:

In protocol.md, change "Melt curve from 65 to 95 °C" to "Melt curve from 65 to 90 °C". Change nothing else.
Commit it with the message "End the melt curve at 90 °C". Then get the latest changes from Gitea (merge, don't rebase) and push.
If Git reports a conflict, stop: don't resolve it yourself. Show me both versions of the lines and who wrote each.

OpenCode's answer: Git reported a conflict while merging from Gitea, so it stopped without resolving it and did not push; ours, by Mia Example: melt curve from 65 to 90 °C; theirs, by jonas: melt curve from 60 to 95 °C; the merge remains paused

You should see: that it stopped without resolving or pushing, and both lines with their authors. Change nothing in this folder until step 16. Without the last line of the request, OpenCode in our test quietly wrote 60 to 90 °C, a line nobody had asked for.

Step 16: Decide. Mia talks to Jonas. His message gives a reason (catch primer dimers) and hers doesn't beat it, so his line stays. She sends:

Keep Jonas's line (60 to 95 °C) and drop mine. Finish the merge with the message "Keep Jonas's melt curve, 60 to 95 °C: it catches primer dimers (agreed with Jonas)" and push. Then show me the last three commits.

OpenCode's answer: resolved the conflict using Jonas's line 60 to 95 °C, created and pushed the merge commit Keep Jonas's melt curve, 60 to 95 °C: it catches primer dimers (agreed with Jonas); below it End the melt curve at 90 °C by Mia Example and Start the melt curve at 60 °C by jonas

You should see: the line 60 to 95 °C, and a merge commit on top with the decision as its message. Mia's own commit stays in the history, so nobody wonders later where 90 °C went.

Step 17: Read the shared history. On Gitea, open Commits again.

Gitea's commit list with commits by mia and jonas: Keep Jonas's melt curve, End the melt curve at 90 °C, Start the melt curve at 60 °C to catch primer dimers, Use master mix with ROX, and Add the plate layout section

You should see: commits by both of you, each with its reason.

Company: the onboarding checklist

Tom (HR) keeps onboarding.md in a repository onboarding; Aylin (IT) is a collaborator.

  • Steps 8 to 11: Tom adds a .gitignore for *.xlsx (salary lists never go in) and pushes a new section First-week meetings.
  • Steps 13 and 14: Aylin changes the laptop line on Gitea; Tom pulls it.
  • Steps 15 and 16: both changed the accounts line on the same day. OpenCode stops; they agree on Aylin's version, because IT owns accounts.

What goes wrong

"Permission denied (publickey)." Symptom: the copy in step 4 fails. Fix: Gitea doesn't know this computer's key. Ask OpenCode to show the .pub line again and compare it with the key under SSH / GPG Keys; add it if it's missing. Check the key is in your account, not a colleague's.

"Host key verification failed." Symptom: the first copy fails before asking anything. Fix: keep the line about accepting the host key once in step 4. If you're unsure it's really your organisation's server, IT can confirm its key fingerprint.

The Review panel shows the whole file as changed. Symptom: on Windows, protocol.md shows every line red and green, although you added five. Fix: the copy was made with Windows line endings. If you haven't changed anything yet, delete the folder and repeat step 4 with the line-endings line. If you have, ask OpenCode: "Set core.autocrlf to false for this repository and restore the line endings as they are on Gitea. Keep my changes."

OpenCode settles a conflict by itself. Symptom: after a push, a line reads something neither of you wrote. Fix: always end a push request with the stop sentence from step 10. If it already happened, open the file on Gitea, correct the line by hand with a message that says what you restored, then decide together.

A data file is already in Git. Symptom: you added .gitignore, but results.xlsx is still on Gitea. Fix: .gitignore only stops new files. Ask OpenCode: "Stop tracking results.xlsx but keep it on my computer, commit that and push." The old version stays in the history; if it held personal data, tell the Gitea administrator (T19-L01, What goes wrong).

A key, token or password went into the chat. Symptom: you pasted one into a message. Fix: treat it as known to others. Click Remove next to the key under SSH / GPG Keys (or change the password). Then ask OpenCode: "Delete id_ed25519 and id_ed25519.pub in my .ssh folder." Only then repeat steps 1 and 2.

SSH is blocked. Symptom: the copy hangs, then times out. Fix: some networks block SSH. Ask IT which port your Gitea's SSH uses, or use the HTTPS route in Details for experts.

Do it yourself (75 minutes)

  1. Set up (20 min, once per computer): steps 1 to 5 with your repository.
  2. Structure it (5 min): your sentence: "When I change ___ on my computer, I want ___ to see it, instead of ___."
  3. Understand it (5 min): for your files, which may go to Gitea and which must stay out? Write them into your .gitignore request.
  4. Choose tools (5 min): OpenCode in Build for your side, Gitea for access and for your colleague.
  5. Build it (40 min): steps 8 to 11 with a real change, then 12 to 14 with your colleague, then provoke one conflict on purpose (steps 15 and 16) and decide it together.

Exit check

A shared repository where: at least one commit was pushed from your computer under your name; a colleague's commit made on Gitea is on your computer; a .gitignore keeps your raw data out; and one same-line conflict was stopped by OpenCode and decided by the two of you. It passes when Gitea's commit list shows all of this, and every message you or OpenCode wrote says why.

Rule to remember

Pull before you push, and when two people changed the same line, a person decides, not the assistant.

Details for experts

Checked on 25 September 2026. You don't need this to follow the book; it's for setting things up or answering a colleague.

WhatDetailsWhat it means for you
VersionsGitea 1.27.2, OpenCode Desktop 2.0.16 with the free Space Bunny model, Git 2.55 for Windows.Newer versions may word answers differently; the requests stay the same.
SSH keyed25519, private half in .ssh/id_ed25519 in your home folder, public half in id_ed25519.pub. No passphrase, so any program running under your login can use the key, OpenCode included.On a shared or unmanaged computer, ask IT for a key with a passphrase and an SSH agent.
SSH addressssh://git@host:port/owner/repo.git, or git@host:owner/repo.git when Gitea uses the standard port 22. The pictures use port 2222 on a test server.Copy the address from Gitea; don't type it.
HTTPS instead of SSHGitea → Settings → Applications → Generate Token with repository read and write. Git then needs a credential helper that stores the token and asks for it outside the chat, such as Git Credential Manager.Never paste the token into the chat. OpenCode turns off Git's own password questions in its commands and terminal, so set the helper up with IT; SSH needs none of this.
Line endingsGit for Windows converts line endings by default (core.autocrlf true). OpenCode's Review panel then compares the Windows version with Gitea's and marks every line.Step 4 turns this off for the repository; editors on Windows handle Gitea's line endings fine.
Merge, not rebaseWhen Gitea has newer commits, Git can rebase (rewrite your commit on top) or merge (add a merge commit). The push request asks for merge, so a conflict ends in a merge commit that carries your decision.Without that word, OpenCode picks one; the content is the same, the history differs.
Collaborator rolesRead, Write, Admin. Organisations and teams come at Level 5.Give colleagues Write; keep Admin for yourself.
GitHubSettings → SSH and GPG keys → New SSH key; repository Settings → Collaborators → Add people. Commit, push and pull work the same.Everything here applies to GitHub; its addresses look like git@github.com:owner/repo.git.

Further reading and tools