---
title: "Version Control II"
subtitle: "Collaboration Workflows with GitHub and gitlab.nrw"
author:
  - name: "Job Schepens"
    id: js
    orcid: 0000-0003-1271-2526
    email: job.schepens@uni-koeln.de
    affiliation:
      - name: Universität zu Köln
        department: CRC 1252 Prominence in Language, Project S
        city: Cologne, Germany
        url: https://jobschepens.github.io/personal-page/
date: "20 May 2026"
date-format: "D MMMM YYYY"
format:
  revealjs:
    theme: [default, ../../stylesheets/mytheme.scss]
    logo: ../../logo.png
    slide-number: true
    scrollable: true
    mouse-wheel: true
    footer: "RDM Workshop Series · SFB 1252 Prominence in Language · Universität zu Köln"
    output-file: slides.html
    embed-resources: true
    transition: none
    background-transition: none
---

## Overview

- **Why** branches, pull requests, and merge requests matter
- **Forks vs branches** — when to use which
- **Collaboration workflows** — from solo to team to open-source
- **Good commit and branch practices**
- **How** to review and discuss changes before merging
- **What** good project structure looks like for shared research repos
- **Hands-on:** opening a pull request / merge request together

::: {.callout-tip}
**Prerequisite:** Basic Git workflow — clone, commit, push (Session 21)
:::


## Recap: Where We Left Off {.smaller}

:::: {.columns}
::: {.column}
**Session 21 covered**

- What version control is and why it matters
- Repositories, commits, remotes
- GitHub vs GitLab vs gitlab.nrw
- Clone → edit → commit → push
:::
::: {.column}
**Today adds**

- Working in parallel without conflicts
- Forks and branches as collaboration tools
- Proposing and reviewing changes
- Organizing shared projects
- Communicating through the platform
:::
::::


## Before We Start: Check Your Git Identity

Git embeds your name and email in every commit. Check they're configured in your tool:

**VS Code:** Open the terminal panel (`` Ctrl+` ``) and run `git config user.name` to check. To set: open **Settings** → search *git user* → fill in `Git: User Name` and `Git: User Email`.

**GitHub Desktop:** Preferences (`Ctrl+,`) → **Git** tab → Name and Email fields.

**RStudio:** Tools → Terminal → type `git config user.name` to check. Set via **Tools → Global Options → Git/SVN** or in the terminal.

::: {.callout-note}
Your identity only needs to be set once per machine. GitHub Desktop usually pre-fills it from your GitHub account.

**CLI:** `git config --global user.name "Your Name"` and `git config --global user.email "you@uni-koeln.de"`
:::


## The Problem with Working on `main`

Two collaborators, one branch — things go wrong fast:

```
Person A: edit → commit → push ✓  (accepted)
Person B: edit → commit → push ✗  (rejected: not up to date)
                    ↓
               git pull → CONFLICT in analysis.R
                    ↓
          must resolve manually before pushing
```

- Mistakes land directly in the shared version with no review
- Hard to separate "finished work" from "work in progress"

> Branches and forks isolate work until it's ready to be shared.


## What Is a Branch?

A branch is a **parallel line of work inside the same repository**.

| Tool | How to create a branch |
|---|---|
| **GitHub Desktop** | Branch menu → **New Branch** → type a name → **Create Branch** |
| **VS Code** | Click the branch name in the status bar → **Create new branch** |
| **RStudio** | Git pane → branch dropdown → **New Branch** |
| **github.com** | Repository → branch dropdown → type a new name → **Create branch** |

- `main` stays stable while you work
- Your work is isolated until you're ready
- Others can review before anything is merged
- Easy to delete after merging — no trace left in `main`


## What Is a Fork?

A fork is a **copy of an entire repository under your own account**.

- Created on the platform (GitHub / gitlab.nrw) with one click
- You have full write access to your fork
- The original repository is unaffected
- You can propose changes back via a pull request / merge request

```
original:   jobschepens/newproject     (you have read access)
your fork:  your-username/newproject  (you have full access)
```


## Forks vs Branches: Key Differences {.smaller}

| | **Branch** | **Fork** |
|---|---|---|
| Lives in | Same repository | Separate copy of the repository |
| Who uses it | Someone with write access | Anyone, including outside contributors |
| Visibility | Visible to all repo members | Lives on your own account |
| Use case | Internal team collaboration | Contributing to repos you don't own |
| Sync with original | No extra setup — pull from the same remote | Manual (`git fetch upstream`) |
| Typical in | Research group repos | Open-source, cross-institute work |

::: {.callout-tip}
**Rule of thumb:** If you have write access → use a branch. If you don't → fork.
:::


## Four Common Collaboration Workflows {.smaller}

| Workflow | Who it's for | Core pattern |
|---|---|---|
| **Centralized** | Small team, everyone trusted | Commit directly to `main` |
| **Feature branch** | Team with code review | Branch → PR → merge |
| **Fork & PR** | Open or cross-institute | Fork → branch → PR → merge |
| **Gitflow** | Software with releases | `main` + `develop` + feature/release branches |

For most **research group projects**: **Feature branch** workflow is the right balance.  
For **contributing to someone else's repo**: **Fork & PR** workflow.

*See Advanced Topics for Gitflow details.*


## Workflow 1: Centralized {.smaller}

Everyone commits directly to `main`. Simple, but fragile.

```
Person A:  edit → commit → push → main ✓
Person B:  edit → commit → push → main ✗ (conflict!)
```

**When it works:**

- Solo researcher
- Very small team with near-zero overlap
- Quick one-off fixes

**When it breaks:**

- Two people edit the same file at the same time
- A mistake goes straight to the shared version
- No review step before changes take effect


## Workflow 2: Feature Branch {.smaller}

The standard for team research projects.

```
main ──────────────────────────────────► stable
        │                       ▲
        └── feature-branch ────►│ (PR → review → merge)
```

**Full cycle in your tool:**

1. **Create branch** — Branch menu / status bar / Git pane → New Branch
2. **Edit files** — work as normal in your editor
3. **Stage & commit** — tick changed files, write a message, click **Commit**
   - GitHub Desktop: left panel → check files → write summary → **Commit to branch**
   - VS Code: Source Control panel (Ctrl+Shift+G) → stage (+) → message → ✓
   - RStudio: Git pane → check boxes → **Commit** → write message → **Commit**
4. **Push** — click **Push origin** / **Sync** / **Push**
5. **Open PR / MR** — platform will show a banner → **Compare & pull request**
6. **After merge** — switch back to `main` and pull to get the latest

::: {.callout-note}
CLI equivalent: `git switch -c branch-name` → edit → `git add . && git commit -m "msg"` → `git push origin branch-name`
:::


## Workflow 3: Fork & Pull Request {.smaller}

For contributing to a repository you do not own.

```
jobschepens/newproject  (original)
        │
        └── fork ──► your-username/newproject  (your copy)
                          │
                          └── branch ──► PR ──► original main
```

**Full cycle:**

1. **Fork** — on github.com / gitlab.nrw: click **Fork** (top right of the repo page)
2. **Clone your fork** — GitHub Desktop: **File → Clone Repository** → choose your fork
3. **Create a branch** — Branch menu → New Branch
4. **Edit, stage, and commit** — same as the feature branch workflow
5. **Push** — **Push origin**
6. **Open PR** — github.com shows a banner on your fork → **Compare & pull request** → target: the original repo
7. **Sync your fork later** — github.com: your fork page → **Sync fork** button; GitHub Desktop: Branch → **Merge into current branch** → choose `upstream/main`

::: {.callout-note}
CLI equivalent: `git remote add upstream <original-url>` → `git fetch upstream` → `git merge upstream/main`
:::


## Good Practices: When and How to Commit {.smaller}

**Commit one logical change at a time**

- Each commit should do *one thing* and be describable in a single sentence
- Don't bundle unrelated edits (e.g., fixing a typo + restructuring a script)

**Commit when the work is in a coherent state**

- After completing a self-contained step: added a function, wrote a section, fixed a specific bug
- Not mid-sentence, not with broken code that won't run
- Think: *"If I had to revert to this commit, would it make sense?"*

**How often?**

- More often is better than less — small commits are easier to review and revert
- A few commits per work session is normal; dozens is fine too
- Avoid "one giant commit at the end of the day"


## Writing Good Commit Messages

```
Bad:   "fixed stuff"
Bad:   "update"
Good:  "Fix participant exclusion logic for Study 1"
Good:  "Add descriptive stats table for German adult data"
```

**Format that works:**

```
Short summary (50 chars or less)

Optional longer explanation after a blank line.
What changed, why, and any relevant context.
```


## Good Practices: Branches and Reviews {.smaller}

**Branch naming**

```
feature/add-exclusion-criteria
fix/typo-in-consent-form
docs/update-readme-methods
```

Use a prefix (`feature/`, `fix/`, `docs/`) so the purpose is clear at a glance.

**Keep branches short-lived**

- Merge or rebase against `main` frequently to avoid drift
- Delete branches after merging — they clutter the repo and create confusion

**Review culture**

- A review comment is not a criticism — it is a question or a suggestion
- Respond to every comment, even if just *"Done"* or *"Disagree, here's why"*
- Approve when you are satisfied, not just when you are tired of reviewing

::: {.callout-note}
Even in a team of two, the habit of reviewing each other's PRs pays off quickly — errors get caught, decisions get documented.
:::


## Good Practices: PR / MR Frequency {.smaller}

**Not per commit, not per day — per logical unit of work**

- Open a PR / MR when a **self-contained piece of work is ready for review**
- This might be a few commits or a few dozen — size matters more than time

**Signs it's time to open a PR / MR**

- A feature, fix, or section is complete and coherent on its own
- You want feedback before going further
- The branch has diverged enough that merging later would be painful

**Keep PRs / MRs small and focused**

- One PR per feature / fix / task — not one PR for everything done this week
- Smaller PRs are reviewed faster and more carefully
- Large PRs ("mega-PR") tend to get rubber-stamped

**Rules of thumb**

| Situation | Recommended cadence |
|---|---|
| Active collaboration | Open a PR after each task (hours to 1–2 days of work) |
| Solo research project | Open a PR at each meaningful milestone |
| Shared writing (docs/papers) | One PR per section or revision round |

::: {.callout-tip}
If in doubt: open early and mark it **Draft** — you get feedback sooner and the review stays manageable.
:::


## Pull Requests and Merge Requests

**GitHub** calls them *Pull Requests* (PRs)  
**GitLab / gitlab.nrw** calls them *Merge Requests* (MRs)  
→ Same idea, different name.

A PR / MR is a **formal proposal** to merge one branch into another:

1. You push your branch (or fork)
2. You open a PR / MR with a description
3. A collaborator reviews and comments
4. Changes are discussed and revised
5. The branch is merged (or closed)


## How to Open a PR on GitHub {.smaller}

**Via github.com (any tool):**

1. Push your branch to GitHub
2. Go to the repository on **github.com** — a yellow banner appears: *"branch-name had recent pushes"*
3. Click **Compare & pull request**
4. Fill in the title and description; set **base** = `main`, **compare** = your branch
5. Assign a reviewer in the right sidebar → **Create pull request**

**Via GitHub Desktop:**

1. After pushing, GitHub Desktop shows a **Create Pull Request** button — click it
2. Your browser opens the PR form on github.com — fill in and submit

::: {.callout-tip}
If the banner doesn't appear: **Pull requests** tab → **New pull request** → select your branch.
:::


## How to Open an MR on gitlab.nrw {.smaller}

**Via gitlab.nrw (any tool):**

1. Push your branch to gitlab.nrw
2. Go to the repository — a blue banner appears: *"You pushed to branch-name"*
3. Click **Create merge request**
4. Fill in the title and description; set **Source branch** = your branch, **Target branch** = `main`
5. Assign a reviewer under *Reviewers* → **Create merge request**

**Via VS Code with GitLab extension:**

1. Push your branch
2. Open the Command Palette (`Ctrl+Shift+P`) → **GitLab: Create Merge Request**
3. Fill in the form that opens in the browser

::: {.callout-tip}
Alternatively: left sidebar → **Merge requests** → **New merge request** → pick your branch.
:::


## Anatomy of a Good PR / MR {.smaller}

:::: {.columns}
::: {.column}
**Title**  
Short, specific, action-oriented  
*"Add regression table for English data"*

**Description**  
- What changed and why
- Any decisions or trade-offs made
- Reviewer instructions if needed
- Links to related issues: `Closes #12`
:::
::: {.column}
**Review checklist**  
- Does the code/text do what it claims?
- Are there errors or unclear sections?
- Are commit messages informative?
- Is anything missing?
:::
::::

::: {.callout-note}
Even solo researchers benefit: a PR forces you to write down *what* you did and *why*.
:::


## Reviewing Changes

On GitHub / gitlab.nrw you can:

- Browse the **diff** — exactly what changed line by line
- Leave **inline comments** on specific lines
- Use **suggestions** to propose exact text changes
- **Approve** or **request changes** before merging

```diff
- participants were recruited via email
+ Participants were recruited via email (N = 48; see consent form).
```


## Merge Strategies {.smaller}

| Strategy | What it does | When to use |
|---|---|---|
| **Merge commit** | Keeps all commits, adds a merge commit | Default; preserves full history |
| **Squash and merge** | Combines all commits into one | Messy branch history |
| **Rebase and merge** | Replays commits linearly on top of main | Clean linear history |

For research work: **merge commit** is usually fine and most transparent.

::: {.callout-warning}
**Rebase rewrites commit hashes.** Never rebase a branch that others are also working on — it rewrites history and will conflict with anyone who pulled the old version.
:::


## Merge Conflicts: What They Are and How to Resolve Them {.smaller}

A conflict occurs when two branches changed the **same lines** of the same file differently.

**VS Code** — opens a visual editor automatically:

- Click **Resolve in Merge Editor** on the conflicted file
- Choose **Accept Current**, **Accept Incoming**, or **Accept Both**
- Save → click **Complete Merge** in the editor toolbar

**GitHub Desktop** — highlights conflicted files in red:

- Click **Open in editor** next to the conflicted file
- VS Code opens with the merge editor (same as above)
- After saving, return to GitHub Desktop → the file is now staged → **Commit merge**

**RStudio** — Git pane shows conflicted files with an orange U marker:

- Open the file — conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) are visible
- Edit manually to keep the correct version, delete the markers
- Stage the file in the Git pane → **Commit**

::: {.callout-note}
Conflicts look scarier than they are — you just choose which version to keep.
:::


## Issues: Tracking Work and Discussions

Issues are not just for bugs — use them for:

- **Tasks:** *"Write methods section for Study 2"*
- **Questions:** *"Should we exclude participants below 18?"*
- **Decisions:** *"Agreed: use APA 7th edition throughout"*

Link issues to PRs/MRs with keywords:  
`Closes #12` in a PR description will auto-close issue #12 on merge.


## Project Structure for Shared Repositories {.smaller}

A clear structure reduces confusion for everyone:

```
my-project/
├── README.md          ← what is this, how to use it
├── data/
│   ├── raw/           ← never modified, version controlled
│   └── processed/
├── scripts/           ← analysis code
├── docs/              ← notes, pre-registrations, papers
├── results/           ← outputs (often in .gitignore)
└── CONTRIBUTING.md    ← how to contribute (for shared repos)
```

::: {.callout-tip}
A good README is often more valuable than comments in code.
:::


## GitHub vs gitlab.nrw: Key Differences {.smaller}

| Feature | GitHub | gitlab.nrw |
|---|---|---|
| Hosting | Public cloud (Microsoft) | NRW university infrastructure |
| Data residency | US servers | Germany / NRW |
| Suitable for | Public/open-source projects | Sensitive or unpublished research |
| CI/CD | GitHub Actions | GitLab CI/CD |
| Account | Personal GitHub account | University login (Shibboleth) |

**Recommendation for CRC 1252:**  
Use **gitlab.nrw** for unpublished data and analysis; **GitHub** for public dissemination.


## Hands-On Exercise {.smaller}

Work in pairs — choose your workflow and tool (GitHub Desktop, VS Code, or RStudio):

**Option A — Feature branch (you have write access):**

1. Clone <https://github.com/jobschepens/newproject> via your tool's **Clone** dialog
2. Create a new branch (Branch menu / status bar / Git pane)
3. Add your name to `contributors.md`, stage and commit
4. Push → open a PR on github.com → have your partner review and merge

**Option B — Fork & PR (external contributor):**

1. Click **Fork** on <https://github.com/jobschepens/newproject>
2. Clone *your fork* via GitHub Desktop: **File → Clone Repository**
3. Create a branch, make a change, commit, push
4. Open a PR from your fork → original repo on github.com

::: {.callout-tip}
Not sure which option? Start with **Option A** — it's the most common workflow.
:::


## Common Pitfalls and How to Avoid Them {.smaller}

| Pitfall | What goes wrong | Fix |
|---|---|---|
| Long-lived branches | Diverges from main, painful to merge | Merge or rebase often |
| Giant commits | Hard to review, hard to revert | Commit small, logical units |
| Force-pushing shared branches | Rewrites history others have built on | Only force-push your own private branches |
| Stale fork | Your fork falls behind the original | Use **Sync fork** on github.com or **Branch → Merge into current branch → upstream/main** in GitHub Desktop |
| No description in PR | Reviewer has no context | Always write at least two sentences |
| Merging without review | Defeats the purpose | Require review before merge (see Advanced: Branch Protection) |


## Summary

:::: {.columns}
::: {.column}
**Concepts**

- **Branch** = parallel work within a repo
- **Fork** = your own copy of a repo
- PRs / MRs formalize the review process
- Issues track tasks and decisions
- Choose workflow by access level and team size
:::
::: {.column}
**The GUI cycle (any tool)**

1. Clone the repo
2. Create a branch
3. Edit → stage → commit
4. Push
5. Open PR / MR on the platform
6. Review → merge
7. Switch back to `main` → pull

::: {.callout-note .smaller}
**CLI reference:** `git switch -c branch` → `git add . && git commit -m "msg"` → `git push origin branch` → `git switch main && git pull`
:::
:::
::::


## Resources

- [GitHub Docs: Collaborating with pull requests](https://docs.github.com/en/pull-requests)
- [GitLab Docs: Merge requests](https://docs.gitlab.com/ee/user/project/merge_requests/)
- [Happy Git and GitHub for the useR](https://happygitwithr.com/)
- [Atlassian: Comparing workflows](https://www.atlassian.com/git/tutorials/comparing-workflows)
- [Conventional Commits](https://www.conventionalcommits.org/) — commit message standard
- [gitlab.nrw documentation](https://git.nrw/en/docs/)


## Further Reading {.smaller}

**Beginner-friendly**

- [GitHub Skills: Introduction to GitHub](https://github.com/skills/introduction-to-github) — interactive, browser-based exercises
- [GitLab tutorial: Make your first Git commit](https://docs.gitlab.com/tutorials/make_first_git_commit/) — step-by-step with screenshots
- [git.nrw beginner level guide](https://git.nrw/en/levels/beginner/)

**Going deeper**

- [Pro Git (free book)](https://git-scm.com/book/en/v2) — ch. 3 (branching), ch. 5 (distributed workflows)
- [Atlassian Git tutorials](https://www.atlassian.com/git/tutorials) — branching, merging, rebasing explained with visuals
- [Oh Shit, Git!?!](https://ohshitgit.com/) — plain-English fixes for common mistakes

**For research specifically**

- [Happy Git and GitHub for the useR](https://happygitwithr.com/) — Jenny Bryan's practical guide, R-focused but broadly applicable
- [The Turing Way: Version Control](https://the-turing-way.netlify.app/reproducible-research/vcs.html) — research-oriented best practices
- [Software Carpentry: Version Control with Git](https://swcarpentry.github.io/git-novice/) — self-paced lesson used in workshops worldwide


---


# Advanced Topics {background-color="#005176"}


## Advanced: Gitflow {.smaller}

Used in software development with versioned releases. Rarely needed for research, but good to know.

```
main      ──────────────────────────── v1.0 ──── v2.0
develop   ──────────────────────────────────────────►
               │              ▲
               └── feature ──►│
```

- `main` only ever contains released, stable versions
- `develop` is the integration branch
- Feature branches merge into `develop`
- Release branches cut from `develop` → `main`

::: {.callout-note}
For a research analysis pipeline with versioned outputs, a simplified Gitflow (just `main` + `develop`) can help.
:::


## Advanced: Staging Part of a File (`git add -p`) {.smaller}

If one file has multiple unrelated changes, you can stage them separately:

```bash
git add -p analysis.R
```

Git shows each change ("hunk") one at a time and asks what to do:

| Key | Action |
|---|---|
| `y` | Stage this hunk |
| `n` | Skip this hunk |
| `s` | Split into smaller hunks |
| `q` | Quit |

This lets a single file produce multiple focused commits — useful when you fixed a bug and refactored code in the same session.


## Advanced: Branch Protection Rules {.smaller}

Branch protection rules prevent direct pushes to important branches and enforce review workflows.

**On GitHub:** Settings → Branches → Add branch protection rule  
**On gitlab.nrw:** Settings → Repository → Protected branches

Common settings for a research repo:

- **Require a pull request before merging** — no direct push to `main`
- **Require approvals** — at least 1 reviewer must approve
- **Require status checks** — CI must pass before merge
- **Restrict who can push** — limit to maintainers

::: {.callout-tip}
Even a two-person project benefits: it makes the PR workflow mandatory and prevents accidental direct pushes to `main`.
:::


## CLI Reference: Feature Branch Workflow {.smaller}

For reference — all steps of the feature branch workflow on the command line:

```bash
# 1. Create and switch to a new branch
git switch -c feature/add-exclusion-criteria

# 2. Stage and commit changes
git add .                    # stage all changes (or: git add filename)
git commit -m "Add participant exclusion criteria"

# 3. Push branch to remote
git push origin feature/add-exclusion-criteria

# → open PR on github.com / MR on gitlab.nrw (web UI)

# 4. After merge: update local main
git switch main
git pull

# 5. Clean up (optional)
git branch -d feature/add-exclusion-criteria
```


## CLI Reference: Fork & PR Workflow {.smaller}

For reference — full fork workflow on the command line:

```bash
# After forking on the platform (web UI):

# 1. Clone your fork
git clone https://github.com/your-username/newproject
cd newproject

# 2. Link the original repo as 'upstream'
git remote add upstream https://github.com/jobschepens/newproject

# 3. Create a branch, edit, commit, push
git switch -c fix/typo-in-readme
git add .
git commit -m "Fix typo in README"
git push origin fix/typo-in-readme

# → open PR: your fork → original repo (web UI)

# 4. Sync your fork after the PR is merged
git fetch upstream
git switch main
git merge upstream/main
```


## CLI Reference: Resolving a Merge Conflict {.smaller}

```bash
# Git marks the conflict in the file like this:
# <<<<<<< HEAD (your branch)
# Participants were recruited via email (N = 48).
# =======
# Participants were recruited via the university mailing list.
# >>>>>>> main

# 1. Open the file and choose which version to keep
#    (delete the markers and unwanted lines)

# 2. Stage the resolved file
git add analysis.R

# 3. Complete the merge
git commit
```

::: {.callout-note}
VS Code, GitHub Desktop, and RStudio all have visual merge editors — you don't need to edit the markers manually.
:::

