Collaborating with Git for group projects

Companion to M02 · pull-first habits, shared repositories, conflict resolution

What this page is for

In M02 you met Git and GitHub as a solo workflow: you commit your changes on your laptop, push them to GitHub for backup, and rarely have to think about anyone else’s edits. That changes when you start your group project. Suddenly two or three people are touching the same .qmd files, and the question of whose changes are where becomes real. This page is meant to make that transition feel manageable.

Read it before your first group-project work session. Then come back to the Daily checklist at the bottom whenever you sit down to work with teammates.

What changes when you go from solo to collaborative

When you work alone in a Git repository, the timeline is simple: every commit you make extends a single straight line of history. Push when you want a backup, pull when you’ve worked on another machine, and there’s never any question about which version is current.

Group work breaks that simplicity. Each teammate’s laptop carries its own copy of the repository, each is making commits, and the shared GitHub repository is the place those parallel timelines get reconciled. The same file can be edited by two people at the same time, and the order in which everyone pushes their changes matters. The two skills that hold this together are:

  • Pulling before you start working — so you’re editing the most recent version of every file, not a stale copy from yesterday.
  • Coordinating who edits what — so you and your teammates rarely touch the same line of the same file at the same time, and conflicts stay rare and small.

The rest of this page unpacks both.

Setting up the shared repository

For a group of two or three students, one person creates the repository and invites the others. The invited teammates then clone the repository to their own laptops — pulling down a complete copy that’s wired up to push and pull from the shared GitHub version.

Which repository are you setting up?

The steps below cover the shared part — inviting collaborators and cloning — and apply to any repository.

Building the project folder itself differs. Your course project already existed as a folder before it became a repository; you turned it into one in the M02 lab. A group-project repository starts from a starter zip: you unzip the skeleton, add an .Rproj, and make it a repository before the first commit. That walkthrough lives in Project setup and reproducibility — do it first, then come back here.

Step 1 · One teammate creates the project repository

Pick one person to be the repo owner for the project. (This is just an administrative role — the owner has no more authority over the analysis than anyone else.) The owner:

  1. Sets up the project folder from the starter zip, following Project setup and reproducibility — that guide is the primary source for group-project structure.
  2. Uses the same GitHub Desktop moves you learned in M02 to turn that folder into a repository.
  3. Pushes the repository to GitHub with Publish repository. Choose Private (only invited collaborators can see it), and keep it private through grading. If your team later wants to make the project public, talk to the instructor first — there are data-use, privacy, and attribution questions to check before anything goes public.

Step 2 · The owner invites the teammates

On GitHub.com (in a browser), the owner navigates to the repository’s page, clicks Settings in the top tab bar, then in the left sidebar finds Access and clicks Collaborators. From there: click Add people, search for each teammate’s GitHub username or email, and send the invitation. (GitHub occasionally rearranges its user interface, so the exact menu path may shift slightly — the destination is Collaborators under the repository’s Settings.)

GitHub emails each invited teammate. The teammates click the link in the email (or visit the repository page) and click Accept invitation.

Step 3 · Each teammate clones the repository

On each teammate’s laptop:

  1. Open GitHub Desktop.
  2. File → Clone Repository…
  3. In the dialog, the GitHub.com tab lists every repository the teammate has access to. The newly-shared one should appear in the list. Click it.
  4. Confirm the local path. GitHub Desktop suggests a default inside your Documents folder — Documents/GitHub/project-1-team-name/ on a Mac, Documents\GitHub\project-1-team-name\ on Windows — where the last part is whatever your team named the repository. That default is fine; change it only if you keep your projects somewhere else.
  5. Click Clone.

GitHub Desktop downloads the repository’s tracked files and commit history to the teammate’s hard drive. It does not download anything .gitignore excludes — above all, the data itself. (M02 covers why: data files are large, sometimes sensitive, and don’t belong in a shared repo — see What NOT to commit.)

The data folders are a different matter, and the two repositories differ here. In a group-project repository, data/raw/ and data/derived/ do arrive — empty, held open by the .gitkeep placeholders — along with the tracked data/README.md saying what belongs in each. That is exactly what those placeholders are for: you need somewhere to put the file the README sends you to go and fetch. Your course project is set up differently, ignoring data/ outright, so there the folder does not come down at all.

This creates a small but important follow-up step: each teammate has to put the data in place locally after cloning, or the notebook’s read_* calls will fail with “file not found.” The code and notebooks are shared through GitHub; the data stay local on each laptop.

How you do that depends on which repository you just cloned:

  • The course project (PSY652_project, from M02) — copy the data/ folder from the bundle you unzipped in M02 into the cloned folder.
  • A group-project repository — each teammate obtains the raw file themselves by following documentation/data-provenance.md, and places it in data/raw/. Then render the main .qmd, which rebuilds data/derived/. Do not email the raw file to each other — for Pew ATP, and for many data repositories, each person must download it under their own agreement.

About the local folder name

When you clone, the local folder you end up with does not have to match the repository name on GitHub. Each teammate can clone into a folder named whatever they like. What links the local folder to GitHub is not the folder name — it’s the hidden .git/ subfolder that GitHub Desktop created, which knows the GitHub repository URL.

The Git connection itself lives inside .git/, so renaming or moving the project folder does not destroy the repository. However, GitHub Desktop tracks the folder’s location separately and may lose track of the folder if you rename or move it. If GitHub Desktop says the repository is missing after a move, use File → Add Local Repository… and point it at the new folder location.

The pull-first habit

The single most important collaborative-Git habit is this: pull before you start working. Every single time.

Why this matters: while you were away from the project — for a day, an hour, even fifteen minutes — your teammates may have committed and pushed changes. If you open RStudio and start editing without pulling first, you’re editing a stale copy of the project. When you eventually push your work, Git has to figure out how to reconcile your edits with the newer history on GitHub — and if you happened to edit the same lines a teammate already edited, you’ve just created a conflict that would not have existed if you’d pulled first.

Pull before you push, too. If a teammate pushed while you were working, GitHub Desktop will ask you to pull before it lets you push — and that is the moment a conflict surfaces, not when you started. Pulling first at the start of a session means you began from current work; pulling again before you push is what reconciles anything that landed while you were busy.

The right rhythm:

  1. Open your laptop. Don’t open RStudio yet.
  2. Open GitHub Desktop first. Click the repository in the left sidebar.
  3. Click Fetch origin (top of the window). This asks GitHub “is there anything new?” — without pulling it yet.
  4. If GitHub Desktop says “Pull origin” (the button label changes), click it. This downloads any changes your teammates pushed since you last looked.
  5. Now switch to RStudio and start working.

Most days this pull-first check takes about ten seconds. (Days when GitHub Desktop pulls down a teammate’s work take a little longer; days with a conflict take a few minutes to resolve.) It is one of the simplest habits that prevents bigger headaches later.

The pull-first habit · phrase it as a rule

“Open GitHub Desktop before RStudio. Pull before you type.”

Say it out loud the first few sessions. After a week, it’s muscle memory.

Commit small, push often

Solo Git can hide sloppy commit habits. Collaborative Git makes them visible.

  • Commit when you’ve finished one coherent thing. A polished figure, a cleaned-up wrangling chunk, a section of prose — anything that “belongs together.” A useful test: if you had to write a commit message in seven words or fewer, could you? If yes, commit. If not, your changes are doing too much at once and should be split into two commits.
  • Every commit is a point you can get back to — and this is the one that will actually rescue you. Sooner or later an edit breaks something that worked twenty minutes ago, and you cannot retrace how. Git can restore a file to its state at any commit, but only as far back as your most recent one: commit every hour and the worst case is losing an hour’s work; commit once a day and the worst case is losing the day. Frequent commits are what turn “I have broken it and I don’t know what I changed” into a minor annoyance. Going back to an earlier version walks through the moves.
  • Push at the end of every work session (and ideally at lunch, at coffee, whenever you take a break). Your teammates can’t see — or build on — work that’s sitting on your laptop. Pushing is how you make your contribution available to the team.
  • Don’t sit on hours of uncommitted work. Uncommitted edits are not just hidden from teammates; they’re not backed up. A laptop dropped in the parking lot at 4:30 PM takes uncommitted work with it.

The combined rhythm: pull → edit → commit → push. Repeat several times a session, not once at the end.

Coordinating who works on what

The simplest way to avoid conflicts is to make sure two people aren’t editing the same file at the same time. For PSY 652 group projects (typically 2–3 students working on one Quarto notebook), three strategies work well together:

  • Divide files by responsibility. Project 1, for example, has a single p1_data_brief.qmd notebook with sections for the question, measurement, the analytic sample, Table 1, the figures, and what the findings mean. Assign each section a primary editor — the person who makes the keystrokes there, which is what prevents most conflicts.

    Primary editor does not mean sole expert. At least one teammate should read and review every section, and by the presentation everyone needs to understand the complete analysis — any of you can be asked about any part of it. Divide the typing, not the understanding.

  • Communicate before opening a file. A quick text or email — “I’m going to edit the wrangling section for the next hour” — is enough. The teammate then waits, or works on a different section. Coordination costs nothing.

  • Make a small commit and push the moment you finish a focused chunk. The longer your uncommitted edits sit, the more likely a teammate has already changed the same file. Frequent commits and pushes keep everyone’s view of the project in sync.

For a 2–3 person team working in a single notebook, you do not need to learn Git branches (a way to maintain parallel timelines and merge them deliberately). The coordination strategies above are simpler and more than enough.

This is a deliberately simplified course workflow: everyone commits directly to the main branch — but only after pulling first and coordinating who’s editing what. Most professional software teams use branches and pull requests (a structured way to propose changes and have them reviewed before merging into main) for larger collaborations; if you take a more advanced course or contribute to an open-source project later, those are the next things to learn.

When conflicts happen anyway

A conflict happens when Git tries to merge two sets of changes and cannot safely decide what the final file should look like. The most common case is when two people edited the same line of the same file. Conflicts can also happen when one person edited a file and another person deleted or renamed it.

This is normal. Conflicts are not a sign you did anything wrong — they usually mean two people edited overlapping parts of the project before those edits were brought together. Resolving them is a five-minute task once you know the shape.

What a conflict looks like in GitHub Desktop

When you click Pull origin and GitHub Desktop discovers a conflict, it stops and tells you: “There are conflicting files in your repository. You can attempt to resolve them in your external editor.”

If you open the conflicting file in RStudio, you’ll see something like this in the middle of it:

The mean SBP in this sample was
<<<<<<< HEAD
131.4 mmHg, slightly above the clinical threshold.
=======
133.2 mmHg, indicating elevated cardiovascular risk.
>>>>>>> origin/main

The lines between <<<<<<< HEAD and ======= are the version currently on your machine — in a pull-from-main workflow like this one, that’s almost always your edits. The lines between ======= and >>>>>>> origin/main are the version from GitHub — usually your teammate’s edits. Git is showing you both and asking you to choose.

Resolving the conflict

  1. Decide what the file should say. Sometimes it’s your version, sometimes it’s your teammate’s, sometimes it’s a combination of both. Sometimes a quick text or email — “Did you mean 131.4 or 133.2?” — is the right move before you decide.
  2. Edit the file in RStudio. Delete the conflict markers (<<<<<<<, =======, >>>>>>>) and leave only the version you want. Save the file.
  3. Switch back to GitHub Desktop. The conflict marker on the file disappears.
  4. Commit the resolution. GitHub Desktop will offer a default commit message like Merge branch 'main' of github.com/.... You can accept it as-is or write something more descriptive (Resolve SBP-mean conflict in wrangling section).
  5. Push. The team’s history now includes both your work and your teammate’s, plus your resolution.

Conflicts feel scary the first time. That reaction is completely normal. After the third or fourth one, they start to feel routine. The most important things to remember are: don’t panic, don’t delete the file, don’t force-push. Just edit the file into the version you want and commit the resolution.

Why you will not get conflicts on the rendered report

Everything above assumes a text conflict you can open and edit. There is one file that would never give you that, and your .gitignore is set up so you never meet it.

The rendered .html regenerates every time anyone renders, and embed-resources: true bakes the figures into it — so two teammates rendering the same source still produce different bytes. If that file were tracked, every push after a teammate’s push would collide on it, Git could not merge it, and hunting for <<<<<<< markers in forty thousand lines of markup and base64 would be hopeless. You would be resolving a conflict about something neither of you had actually changed.

That is exactly why programs/*.html is in your .gitignore. The report stays untracked while you work, and in your final week you delete that one line, have one person render, and commit the result. Project setup and reproducibility has the steps.

If you ever do face a conflict on a generated file — an exported .png in output/figures/, say — do not hand-edit it. The fix is a different shape:

  1. In GitHub Desktop, resolve the conflicted file by taking either version. It genuinely does not matter which.
  2. Commit that resolution.
  3. Regenerate the file by re-running the code that produces it.
  4. Commit the regenerated file and push.

A generated file has no “correct merge” — the correct version is whatever the current source produces. You are not reconciling two documents; you are clearing the jam and regenerating. If the .qmd is conflicted too, resolve that first — it is a text file, so use the ordinary procedure above — and only then regenerate.

When something isn’t working

Conflicts get the most attention, but four other things go wrong far more often — and all four look alarming while being quick to fix.

“GitHub Desktop says there are no changes”

You edited a file and the Changes tab is empty. Work down this list:

  1. Is the file saved? RStudio shows your edits on screen while the file on disk is unchanged, and Git only ever sees the disk. An unsaved file shows its name in red with a dot beside it. Press Cmd/Ctrl + S and look again. This is the most common cause by a wide margin.
  2. Are you editing the folder GitHub Desktop is watching? In GitHub Desktop, Repository → Show in Finder (Windows: Show in Explorer). In RStudio, type getwd() in the Console. If those two paths are different, you have two copies of the project and have been editing the one Git is not tracking.
  3. Is the right repository selected? GitHub Desktop shows the current one in the dropdown at the top left.
  4. Is the file one Git is set to ignore? Anything inside data/raw/ or data/derived/, and — until your final week — programs/*.html. Those are missing on purpose.
  5. Has GitHub Desktop simply lost track? Press Cmd/Ctrl + R to refresh, or quit and reopen it.

“It won’t let me push”

If it asks you to pull first, a teammate pushed while you were working. That is ordinary, not an error: click Pull origin, let it merge, then push. If you both changed the same lines you will get a conflict — see above.

If it says you are not signed in, or the push just fails, your account has become disconnected. Open Settings (Windows: Options) → Accounts and sign in again.

“My teammate can’t see my work”

Committing is not sharing. A commit records the change on your own laptop; the push is what sends it to GitHub. If teammates cannot see something you finished, it is almost always committed but not pushed — look for Push origin at the top of GitHub Desktop with a number beside it.

The mirror image is just as common: if you cannot see their work, you have not pulled.

“I can’t clone the repository”

Check that you accepted the invitation. GitHub sends it by email and it lands in spam more often than you would expect — you can also accept by visiting the repository’s URL while signed in. Until you accept, a private repository is invisible to you and will not appear in GitHub Desktop’s list of repositories to clone.

Fifteen minutes, then ask

None of these is worth an evening. If the list above has not sorted it out in about fifteen minutes, bring it to lab or email us — and say what you have already tried, which usually tells us where to look immediately.

Commit message hygiene

Every commit you make becomes a permanent line in your repository’s history. Six months from now, you (or a teammate, or your future advisor) will scroll through the history looking for when did we change the regression model? — and your commit messages are the only thing that will help.

Bad Better
Update Drop participants under 18 from analytic sample
fix Fix legend title in main bar chart
more changes Add gender × age-group interaction to wrangling chunk
final Set final figure caption per professor's feedback

A useful template for a commit message: a verb in the imperative, followed by what changed, optionally followed by why. “Add age-group recoding to wrangling chunk so adults can be filtered by life stage.” The “why” part is what makes a commit message valuable to future-you.

A few rules of thumb (the don’ts)

  • Don’t push broken code. Before you push, render your .qmd to confirm it still builds. If the render fails, fix it before pushing. Pushing broken work means the next teammate who pulls it has a broken project too — and they may not realize the breakage is yours, not theirs.
  • Don’t push data files. The starter’s .gitignore keeps everything inside data/raw/ and data/derived/ out of Git (M02 covers this), so a .sav, .csv, or .rds should never appear in GitHub Desktop’s Changes list. Two things under data/ are tracked on purpose — data/README.md and the .gitkeep placeholders — so seeing those is correct, not a problem. But a teammate who edits the .gitignore, or builds a repo from scratch, can undo the protection: if an actual data file shows up under data/raw/ or data/derived/, stop and ask before committing.
  • Never force-push main. A force-push rewrites the shared history and can erase a teammate’s commits. GitHub Desktop will sometimes ask about “forcing” a push when its normal one is blocked. In this course the answer is always no. Pull, resolve any conflicts, and push normally — and if GitHub Desktop insists a force-push is required, stop and ask for help rather than agreeing to it.
  • Don’t commit credentials. API keys, passwords, anything secret should never enter your repository.

Daily checklist for collaborative work

Every group-project work session

Before you start:

  1. Open GitHub Desktop before RStudio.
  2. Click Fetch origin. If “Pull origin” appears, click it.
  3. Now open RStudio.

While you work:

  1. Stay in the file(s) your team has assigned you.
  2. Commit every time you finish a coherent chunk (a figure, a wrangling step, a paragraph). Write a real commit message.
  3. Render your .qmd periodically to make sure it still builds.

Before you stop:

  1. Render one last time. Fix any errors.
  2. Commit your final changes.
  3. Click Push origin.
  4. Tell your teammates what you worked on — text, email, whatever your team agreed on — so they know what to pull next.